`* * * NOTICE * * *` `* * * WARRANTY * * *` This software program(s) is warranted to perform as documented when used on the speci- fied hardware operating under the specified disk operating system as shown on the accom- panying documentation. If within 90 days of the date of purchase the program is found to be defective due to a bug in the code, the pub- lisher will, upon request, provide a patch to correct the bug or will update the program diskette with a corrected copy within a rea- sonable time period after return of the program diskette to the publisher. If within 90 days of the date of purchase the documentation proves defective due to missing pages, the publisher will provide substitutes for the missing pages upon request. The publisher shall have no liability or responsibility to the purchaser or any other person, company, or entity with respect to any liability, loss, or damage caused or alleged to have been caused by this product, including but not limited to any interruption of service, loss of business and anticipatory profits, or consequential damages resulting from the oper- ation or use of this program. `* * * ATTENTION * * *` This program package is copyrighted with all rights reserved. The distribution and sale of this program is intended for the personal use of the original purchaser only and for use only on the computer system noted herein. Fur- thermore, copying, duplicating, selling, or otherwise distributing this product is ex- pressly forbidden. In accepting this product, the purchaser recognizes and accepts this agreement. The purchaser is entitled to make as many working copies of this disk as is needed for his or her personal use. `MISOSYS,Inc.` `P.O. Box 239` `Sterling, Virginia 22170-0239` `703-450-4181` MC C-Language Compiler Reference Manual Copyright (C) 1985 by MISOSYS, Inc., All rights reserved Reproduction in any manner, electronic, mechanical, magnetic, optical, chemical, manual, or otherwise, without written permission, is prohibited. Published by: `MISOSYS, Inc.` P. O. Box 239 Sterling, Virginia 22170-0239 703-450-4181 `* * * A T T E N T I O N * * *` The MC compiler can be used to generate any software product, commercial or other wise, without payment of any royalties to MISOSYS, with the exception of the following: when MC is used to generate another compiler product, no part of the MC-supplied libraries may be included in the run-time support of the generated compiler. MC compiler: Copyright 1985 R. N. Deglin, All rights reserved. MC Libraries (LIBA/REL, CLIB/REL, MATH/REL, IN/REL): Copyright 1985 R. N. Deglin and MISOSYS, Inc., All rights reserved. MC is a trademark of MISOSYS, Inc. LDOS is a trademark of Logical Systems, Inc. TRS-80 and TRSDOS are trademarks of Tandy Corporation. UNIX is a trademark of Bell Telephone Laboratories. `Table of Contents` Introduction ......................................... 1- 1 MC Provided Files ................................. 1- 2 MC Environment .................................... 1- 6 Standard Input/Output ............................. 1- 7 Standard I/O Redirection .......................... 1- 8 Command Line Arguments ............................ 1- 9 Standard Header Files ............................. 1-10 Function Libraries ................................ 1-11 Runtime Error Control ............................. 1-12 Closing Comments .................................. 1-14 Language Definition .................................. 2- 1 Program Environment - Functions ................... 2- 1 Statements - Simple & Compound .................... 2- 3 Data Representation - Constants ................... 2- 4 Variable Names (Identifiers) ...................... 2- 6 Data Declarations ................................. 2- 7 Scope of Variables & Functions .................... 2-14 Storage Classes ................................... 2-15 Expressions ....................................... 2-18 Unary Operators ................................... 2-22 Binary Operators .................................. 2-25 Statements ........................................ 2-30 IF ............................................. 2-31 SWITCH-CASE .................................... 2-32 WHILE .......................................... 2-33 DO-WHILE ....................................... 2-33 FOR ............................................ 2-34 BREAK .......................................... 2-34 CONTINUE ....................................... 2-35 RETURN ......................................... 2-35 GOTO ........................................... 2-36 MC Preprocessor ................................... 2-37 #define ........................................ 2-38 #undef ......................................... 2-41 #if ............................................ 2-41 #ifdef, #ifndef ................................ 2-42 #else .......................................... 2-42 #endif ......................................... 2-43 #include ....................................... 2-43 #option ........................................ 2-44 #asm, #endasm .................................. 2-45 #line .......................................... 2-46 Program examples: sortsym, dcal ................ 2-47 MC Operators Guide (Running the Compiler) ............ 3- 1 Keyboard Refresher ................................ 3- 1 MC Operation ...................................... 3 -1 Using Job Control Language ........................ 3- 3 Invoking the MCP Preprocessor ..................... 3- 4 Invoking the MC Compiler .......................... 3- 6 Creating an Executable Command File ............... 3- 8 Compile Time Directives ........................... 3- 9 Assembly of the ASM file .......................... 3-11 Linking the Relocatable Object Module ............. 3-11 MC Library ........................................... 4- 1 General ........................................... 4- 1 Functions [abort() to zero()] ..................... 4- 4 `First Edition` Advanced Topics ...................................... 5- 1 Runtime Options and I/O Control ................... 5- 1 Call: DOS SVC Interface ........................... 5- 7 Separate Compilation of Modules ................... 5- 7 Using extern and static ........................... 5- 9 Building and Maintaining Relocatable Libraries .... 5-11 Programs with overlays ............................ 5-13 When things go wrong .............................. 5-16 Runtime error traping ............................. 5-18 Assembly Language Interfacing ..................... 5-22 Program Memory Map ................................ 5-23 MC Identifier Output .............................. 5-24 Runtime variable storage format ................... 5-24 Register Utilization .............................. 5-25 Argument passing .................................. 5-26 Returning a value from a function ................. 5-27 Appendix Error Messages .................................... A- 1 `First Edition` `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` General Congratulations! You have purchased the finest C compiler package available for your machine environment. MC will prove itself to be a valuable investment of your software dollars. Thus, before diving into MC, we suggest that you follow the guidance expressed in the following paragraphs. Read the entire introduction to get an idea of what MC is all about. This will provide an immeasurable insight into the C programming power available to you with the MC compiler. It may also help you understand the content of the remaining chapters. MC requires the use of a macro-assembler which generates Microsoft com- patible relocatable object module files. An assembler is not included with the compiler package. You may have purchased the MISOSYS "Relocating Macro Assembler Advanced Development System" (MRAS) or Microsoft's M-80 assembler. If you have neither, you will not be able to use the compiler package until you obtain a copy of either MRAS or M-80. C source code is prepared using the editor which is included with your assembler package. Make backup copies of the MC distribution diskette to use as a working master. The compiler package is released on a 40-track double density DOS data diskette. This diskette contains all of the files associated with the compiler. We suggest that you make one set of archival backups and store them away in a secure area (safe from dust, dirt, magnetic fields, etc.). Then make a working backup of the distribution diskette. The procedures for making backup copies can be located in the UTILITY section of your DOS user manual under "BACKUP". If you are going to use MC with MRAS, delete "MC/MAC" and "MCMACS/MAC" from the working disk. Conversely, if you are going to use MC with M-80, delete "MC/ASM" and "MCMACS/ASM" from the working disk. If you are usinge MC on a two drive floppy system, you will have to create a DOS system diskette with a maximum of free space. This "working system diskette" can be created by using the DOS PURGE utility on a fresh backup of DOS. You may remove all files except SYS0-SYS4, SYS6, SYS8 (SYS8 can be removed from TRSDOS 6.x), SYS10-SYS12. A 40-track double density minimal system diskette per the above has about 144K free. Copy your assembler, linker, and editor from your assembler disk. Then copy the MC/JCL file and the compiler command files from the working backup to this system diskette. If there is still space left on your system disk, copy some of the other files from the work disk. You will not be able to copy all of the files; in fact, most will still be on the working disk. If your machine has 128K and you are using a RAMdisk, you will find it beneficial to copy the library /REL files to your RAMdisk. Once this is done, remove the files from the working data disk that were copied to the system disk. This should leave work space on the data diskette in your second drive for C source files and the files generated during the programming session. Notice that MC requires a two drive system. In fact, you may find it prudent to use MC on a three drive system - or one using two-sided drives - or even a hard disk environment. If you have gotten this far, continue to read this chapter and discover everything that MC provides you with. `Introduction - General` 1 - 1 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` MC Provided Files MC is a complete C compiler. It adheres to the "standards" expressed by Brian Kernighan and Dennis Ritchie in their book, "The C Programming Lang- uage". MC includes an extensive UNIX System V compatible function library. All you need to generate executable CMD programs is a macro assembler which generates Microsoft compatible relocatable object modules. There are many files on your distribution diskette. In fact, in order to make room for all of the files, the header files have been merged together into a single source archive file. The following C program (which may be on the disk, space per- mitting) will separate the archive into the individual header files: /* unarc.ccc - 11/29/85 */ char aline[81]; main() { while (gets(aline)) { if(!strncmp(aline,"/*%",3) && gets(aline)) { if (!freopen(strcat(aline,":3"),"w",stdout)) exit(-1); else { fputs("\nGenerating: ",stderr); fputs(aline,stderr); } } else puts(aline); } } Once you have established your working compilation and assembly system, the unarc program should be typed into a file named "unarc/ccc". You may change the ":3" which appears in the sixth line of unarc to specify which output drive the header files should be written to. Then compile unarc with the DO command: "DO MC (N=UNARC)". After the command program has been successfully created, invoke unarc with the command: UNARC ", causes substitution of the standard output file specification, the ">>" causes standard output to be appended to the redirected file/device, and the number sign symbol, "#", causes substitution of the standard error file specification. Spaces are permitted between the redirection character and the file specification. It may not be immediately obvious how this feature can be used. Here is an example C program that illustrates the straightforward use of standard I/O redirection. The following program can be used to copy any file to any other file (remember that "file" can be any device or DOS disk file). /* CLONE - copy standard input to standard output */ #include stdio.h int c; main () { while ((c = getchar()) != EOF) putchar(c); } The example program simply copies the standard input to the standard output until end of file is reached. Once this program is compiled, assem- bled, and linked, it can be used to copy any file to any other. For example: CLONE *PR lets the user type to the system printer. If disk file copying is needed, the command: CLONE OUTFILE/BAK:2 will copy the file "INFILE/ASM:1" to the file "OUTFILE/BAK:2". If the user wishes to have a printed log of any error messages that a program puts out, use something like : MC TESTLIB #*PR Any messages that MC outputs to the standard error file will be re-directed to the printer device in lieu of the console display. `Introduction - Standard I/O Redirection` 1 - 8 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Command Line Arguments When a C program is invoked, the command line is parsed into a list of arguments. A single argument is represented by a continuous string of non-white space characters surrounded by white space. At a minimum, a command invocation will have one argument - the program name itself. The list of arguments is passed to the executing program through the "argc" and "argv" arguments of main(). "Argc" is an integer which contains the number of arguments while "argv" is an array of elements, each element of which is a pointer to a character string. These arguments will usually be declared as: main(argc,argv) int argc; char *argv[]; providing your program with a method of recovering various data entered on the command line by the invoker. Command line arguments to a C program may be enclosed in single or double quotes. This allows the inclusion of special characters and whitespace in an argument. The quotes are stripped before the argument is passed to main(). To include a quote in an argument, precede it with a backslash "\". To include a backslash, use a double backslash "\\". For example, in a command line such as: PROCESS INPUT/DAT:3 TEMPY/TXT:5 +O=:7 -L "+C=This is a message" six arguments will be passed to main() and "argc" will be equal to 6. If main() was the program: main(argc,argv) { while (argc--) puts(*++argv); } it would output the strings, "PROCESS", "INPUT/DAT:3", "TEMPY/TXT:5", "+O=:7", "-L", and "+C=This is a message". Note that the latter argument is a text string having imbedded blanks; this is permitted when the command line argument is enclosed within quotes. Any redirection specifications will be processed before the command line arguments and will not appear in the argument list. `Introduction - Command Line Arguments` 1 - 9 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Standard Header Files Standard header files are files which contain definitions peculiar to a system. They usually take the form of "#define" statements and "extern" statements within the header file. In order to use certain libraries, a corresponding header file should be included (using the "#include" state- ment). The file extension of "/H" is used for MC header files to be consis- tent across versions of UNIX and other systems sporting C compilers. A program to be compiled and linked with MC should usually have the file "STDIO/H" included to compile properly. STDIO/H also defines various system dependent parameters, such as end of file (EOF) and end of line (EOL). The FILE POINTERS , , and are addresses in the standard library which do not need to be defined before use; however, the FILE DESCRIPTORS , , and are defined in the header file. MC includes many header files which are standard under UNIX. These files contain symbolic definitions of constants used in various functions in the stanard library. It is absolutely essential that you use the symbols defined in the header files when noted in the documentation for the functions. Do NOT extract the symbolic constant's value and use the number in your program. Numbers are not necessarily portable across C installations; however, the symbolic NAMES are a part of the AT&T definition and are portable! Thus, by using the symbolic names defined in the appropriate header files, you will minimize any conflict in portability, not to mention compatibility with future releases of this compiler package. Any header file required by a function is documented with the function needing it. `Introduction - Standard Header Files` 1 - 10 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Function Libraries Commonly used functions are collected into FUNCTION LIBRARIES. The functions in a library can be used by the programmer without the need to rewrite, recompile, or reassemble the functions needed. Once a C program has been compiled and assembled, it can then be combined during the link phase with the functions it requires. Only those functions necessary for the execution of the program are linked to the compiled program. Certain functions required by many programs are included in a special library called the STANDARD LIBRARY. The standard library is the common denominator among all C language installations. Programs written using functions in the standard library are easily transported to any other compu- ter supporting a C language system with the standard library implemented. The most important aspect of the standard library is that it allows the details of each system's peculiar operating environment to be hidden from the pro- grammer's view. The standard library provides the functions for input/output, memory allocation, and character set manipulations. What is typical in UNIX installations is to have the standard functions "callable" from C in a library named "LIBC". In addition, a collection of subroutines used by the compiled C program to perform basic operations but not directly callable from C is contained in a library named "LIBA". MC fol- lows these standards. MC also incorporates the high-level math functions into a "MATH" library as is also found under UNIX systems. Users can also create their own collections of often-used functions that can be used in the same manner as the standard library. These USER LIBRARIES reduce the programming time, compilation time, assembly time, and program complexity necessary in creating new programs. Functions, once defined, written, and tested, can be added to the user library and need only be referred to by name in later programs. The linking process brings the func- tions into subsequent programs without the need to recompile and reassemble. Relocatable object module libraries are created and maintained using the MLIB librarian. This facility is included with the MRAS assembler package or is available separately for M-80 users. You can even build a user library with the APPEND command in the DOS by using the (STRIP) parameter. More on library building is included in Chapter 5, "Advanced Topics". Special purpose libraries may also be created for use in particular types of applications. For instance, the functions specific to the hardware are provided with your C package are in the special purpose library, IN/REL. This is an example of how the C language avoids the trap of non-standard extensions being included within the language. `Introduction - Function Libraries` 1 - 11 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Runtime Error Control MC provides certain facilities for the detection and control of four types of runtime errors. These errors may be classified as DOS I/O errors, C environment errors, low-level floating point errors, and high-level floating point mathematical errors. This section will describe the function and purpose of the control the programmer has over these errors; however, the mechanics of implementing the control will be discussed in Chapter 5, "Advanced Topics". To begin with, the standards of UNIX System V dictate a protocol for most functions to return a value indicating that an error ocurred. Chapter 4, "Function Libraries", documents the error return conditions for each function which supports an error return code. It is up to the programmer to provide appropriate code to detect and act on that error return code. The DOS I/O errors are characterized by problems in accessing files, reading from files, or writing to files. When such an error is detected in the MC I/O package, the DOS I/O error is stored in the File Control Area assigned to the file stream, provided the file has been successfully opened. This error number may be obtained through the ferror() function. Next, the error is passed to a routine in the I/O package which will optionally display the runtime error. The option() function provided in the standard library can be used to control the behavior of this I/O error display - or suppress it entirely. Next, the DOS I/O error will be translated to an appropriate UNIX error number and stored in the global error variable, "errno". Finally, the error indication will be reported back through the highest library function invoked to return an indication of error to your program. There are other types of errors which could be experienced. A memory allocation request could be unsatisfied because insufficient free memory was available. A request to obtain status on a file stream could be unsatisfied because the request was associated with a "character special device" (i.e. *DO) rather than a file. These types of errors have an appropriate UNIX error number assigned. Thus, any of these errors will store the designated UNIX error number in the global error variable, "errno". The error indication will be reported back through the highest library function invoked to return an indication of error to your program. On larger computers, floating point errors such as overflow and underflow are usually trapped by hardware. When detected, they generate a hardware interrupt so software routines can be notified to take whatever action is desired. Since all of the floating point routines provided in MC are implemented in software, your computer cannot generate a hardware interrupt when a floating point error ocurrs. When MC does recognize a low-level floating point error, it stores an error code in "errno", the global error variable. In addition, MC provides a floating point vector, "_fltvec", which is called whenever such an error has been detected. This vector can be altered by your program to point to your function which takes whatever action you decide to implement. In its normal state, "_fltvec" does nothing but return. The fourth facility for trapping errors is provided by "matherr()". High-level floating point errors are characterized by such things as trying to take the square root of a negative number, trying to take the log of a `Introduction - Runtime Error Control` 1 - 12 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` negative or zero number, or trying to take the Arc sine of a value which is not in the range extending from minus one through plus one. UNIX System V documents a floating point exception handler, called matherr(), which is called when such high-level mathematical errors are encountered. An exception structure contains information pertinant to the detected error at the time that matherr() is invoked. The global error variable, "errno", is also loaded with the appropriate error number. In addition, a uniform error message is optionally written to standard error. Your program may provide its own matherr() function to handle the detected error as you see fit. Illustrations of this facility appear in the documentation of those functions which support this high-level floating point exception handling. It should have been evident from this discussion that all error types make use of the global error variable, "errno". This variable is a UNIX System V feature. All of the error numbers are represented by symbolic values and appear in the "errno" header file. The "math" header file defines the exception structure and the symbolic definitions of math errors. These header files should be "#include'd" with your source program as appropriate in order to make use of the symbolic definitions. `Introduction - Runtime Error Control` 1 - 13 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Closing Comments C encourages the use of structured programming methods. Unless one uses the "goto" statement heavily, C practically demands a structured approach to program construction. This is not to say that writing programs in C will automatically make you a good, structured programmer. This is a skill that is developed by learning and applying the basics. Some understanding of structured design concepts is necessary in order to effectively use C. Probably the first frustrating thing that novice C programmers will encounter, especially if their experience is limited to BASIC and assembly language, is the discouragement of the use of "goto". Kernighan and Ritchie, in THE C PROGRAMMING LANGUAGE, state that the "goto" is never necessary, and in practice it is almost always easy to write code without it. The concept to understand is that the "goto's" are hidden within the program statements. C provides, in a coherent, understandable form, the program constructs that you have been building out of "goto's". Last but not least, many texts are available that can be part of your library. The following list is not to be considered all inclusive but lists those texts (alphabetically) that we have had at our disposal. THE BIG RED BOOK OF C by Kevin Sullivan (published by Sigma Press) THE C PRIMER by Les Hancock and Morris Krieger (published by BYTE Books). C PRIMER PLUS by Michael Waite, Stephen Prata, and Donald Martin (published by Howard W. Sams & Co., Inc.) C PROGRAMMER'S LIBRARY by Dr. Jack Purdum, Timothy C. Leslie, and Alan L. Stegemoller (published by Que Corp.). C PROGRAMMING GUIDE by Dr. Jack Purdum (published by Que Corp.). THE C PROGRAMMING LANGUAGE by Brian W. Kernighan and Dennis M. Ritchie (pub- lished by Prentice-Hall). We will refer to this book throughout this manual by the abbreviation, "K&R", for Kernighan and Ritchie. THE C PUZZLE BOOK by Alan R. Feuer (published by Prentice-Hall). INTRODUCTION TO C by Paul M. Chirlian (published by MATRIX) LEARNING TO PROGRAM IN C by Thomas Plum (published by PLUM HALL). SYSTEM V INTERFACE DEFINITION (published by AT&T) THE UNIX PROGRAMMER'S MANUAL Volume I and Volume II by Bell Telephone Laboratories, Inc. (published by Holt, Rinehart and Winston). `Introduction - Closing Comments` 1 - 14 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Program Environment - Functions The C language is, in a word, functional. The basic unit of program construction when using C is the function. Every C program is a collection of functions. Each function is a collection of statements that work together to achieve (hopefully) a useful, well-defined, purpose. Each function can have information passed to it when it is invoked ("called"). The elements of information passed to the called function are denoted as arguments. In C, arguments are copied onto the stack. The function can then access and use the "local" (known only to the called function) arguments, leaving the original copy of the arguments unchanged. Each argu- ment is defined at the start of the function. Functions also return values to the functions that call them. In C this value can be an integer number, a long integer, a float, a double, or a pointer. The value returned can be compared to, placed in a variable, etc. Functions can appear in an arithmetic expression anywhere that a constant can. Here is an example of a function: square(num) int num; { return num * num ; } The function, square(), returns the square of a number; in other words, the argument, "num", is multiplied by itself and the result is returned. Arguments are listed in parentheses after the name of the function, separated by commas. These arguments must be passed by the calling function in the same order as they appear in this list. The BODY of the function is the group of executable statements that are within the braces "{" and "}". Actually, the grouping of statements in be- tween braces denotes a special kind of statement called the COMPOUND state- ment. The compound statement is fully explained in the section on C language statements. Every C program has a special function called "main" which is always the entry point to the program. When referencing a function within this narra- tive, we will put "()" after the name to identify it as a function. This is close to the way it looks in a C program. The function, main(), calls other functions, which in turn call other functions, etc... Thus, each program is a hierarchical structure of functions, with main() at the top of the hierarchy. The DOS command line which invokes the C program is passed to the func- tion main() using two parameters, "argc" and "argv". One C program can invoke another program by using the system() function. When the called program fin- ishes, a special function, exit(), is used to return a value to the calling program. Programs can call other programs, passing any information using "argc" and "argv" command line arguments as explained in Chapter 1, "Intro- duction". In a way, each program appears as a function to other C programs and to the DOS. `Language Definition - Program Environment` 2 - 1 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Please scrutinize the illustration of functions in the following example: main() { /* The "main" function ... execution begins here! */ say_hello(); do_work(); say_goodbye(); exit(0); /* a normal exit, no error code */ } /* sorry, we can't "goto" any of the functions below. */ say_hello() { puts("Hiya!!!"); } say_goodbye() { puts("Bye y'all!!!"); } do_work() { while (not_quitting_time) { attach(nut,bolt); pass_on(widget); } } `Language Definition - Program Environment` 2 - 2 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Statements - Simple and Compound To create a C function, you have to state the action to be taken using C language STATEMENTS in the desired combination. Certain special statements are built into the language to provide the necessary programming constructs (sequence, iteration, selection). You may be surprised, at first, by the limited number of statements built into the C language. The authors of the language wished to maintain the generality of the programming statements, forcing any special features to be outside of the programming language it- self. Other languages often have extensions in the form of statements to provide specialized features, leading to incompatible versions of the same language. BASIC is a well-known example of a language extended in far too many different ways. The C language avoids this situation by only providing those statements necessary for structuring the program's logical flow and by placing all special features into function LIBRARIES. Function libraries are nothing more than collections of commonly used functions. Simple C statements always end with a semicolon ";", the STATEMENT TERMINATOR. The C compiler depends on the semicolon to tell when a simple statement ends. Any number of simple statements may be entered, one after the other, to form a SEQUENCE of statements that are executed one at a time, first to last. The brace characters, "{" and "}", are used to enclose a sequence of statements to form a COMPOUND statement. A compound statement can be used anywhere a simple statement can be used. Thus, the body of a function (that portion enclosed in braces) is just a special form of compound statement. For example: nl = 0; is a simple statement. However, the statement: { h = h / 2; x0 = x0 + h / 2; y0 = y0 + h / 2; x = x0 + i * 32; y = y0 + 10; u = x; v = y; ++i; p( 1, i ); } is a compound statement. `Language Definition - Statements` 2 - 3 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Data Representation - Constants Numbers and characters must be entered in your C program in certain ways in order for the compiler to understand them properly. A fixed value to be used in a C expression is called a CONSTANT. Where an integer number is required, you enter it just as you write it. A leading zero indicates that the constant is in a base other than decimal. A leading zero followed by a string of digits indicates an OCTAL CONSTANT. A leading zero followed by 'X' or 'x' indicates that a hexadecimal constant follows. Thus, the decimal number, 255, can be represented as 0377 or 0xFF, as desired. A long integer constant should be terminated with the uppercase letter "L" or the lowercase letter "l" as in 1234567L or 0x2a009105L; how- ever, an integer value greater than 65535 will be considered a long. Floating point constants have the syntax of an optional sign, followed by a string of decimal digits possibly containing a decimal point, an optional exponent field containing an 'e' or 'E' followed by an optionally signed decimal integer. If the variable to be assigned the constant is not big enough to contain the constant, only the least significant bits (LSB) of the number are stored. This is, in effect, storing the remainder of dividing the constant by 256 or 65,536 or 4,294,967,296 depending on the variable size. No warning is given when this happens (except in the case of floating point overflow errors which can be trapped by the program), so the programmer must be sure that the variable can hold the number. CHARACTER CONSTANTS supply a way to specify the code for a character which does not depend on any particular character set. A character constant is a list of characters within single quotes (apostrophes). For instance, the character constant 'A' is stored in the computer as the number 65 (in deci- mal). Again, it is up to the programmer to assure that the number of charac- ters between apostrophes can fit into the variable being assigned. If more characters are specified than can fit, only the last one or two (as needed) are used. When a sequence of characters is needed, a STRING can be specified by enclosing the characters between quotes (sometimes called "double" quotes - i.e. "This is a string"). C does not place all of these characters into a variable but rather uses the ADDRESS of the first character of the string. Thus, when the string, "testing, 1 2 3", is used in an C program, the char- acters between quotes are stored in memory, and the address of the first 't' is used in the expression where the string was specified. You can say that the number generated by C to represent the string really POINTS to the string. The subject of POINTER variables, which are handy for manipulating strings, will be discussed later. There are certain control characters that are needed frequently in pro- grams, but which differ from machine to machine. These can be represented in C programs using ESCAPE SEQUENCES, to provide a machine-independent constant. The backslash character, "\", is called the ESCAPE CHARACTER and denotes the beginning of an escape sequence. A letter following the escape character in- dicates which control code is being specified. Also, certain characters that would otherwise be difficult to represent in strings and character constants are generated by following the backslash with the character. These escape `Language Definition - Data Representation` 2 - 4 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` sequences are shown in the following table: _____________________________________________________________ | | | Escape | | Sequence Control Code ASCII code used by C | | -------- ----------------- -------------------- | | | | \n,\N NEWLINE character x'0D' CR | | \t,\T horizontal tab x'09' HT | | \b,\B backspace x'08' BS | | \r,\R carriage return x'0D' CR | | \f,\F form feed x'0C' FF | | \\ backslash x'5C' backslash | | \' single quote x'27' apostrophe | | \0 null x'00' null byte | | \" double quote x'22' double quote | |_____________________________________________________________| In addition, any binary code can be represented in a string or character constant by following the backslash with a numeric constant. This is done by following the backslash with up to three octal digits. An extension which is not normally allowed in the C language is offered in MC as a convenience to microcomputer users who are only familiar with hexadecimal. The backslash may be followed by an 'x' and one or two hexadecimal digits. Either of these two methods result in an 8-bit character constant. For example, the character 'A' can be represented as '\x41' using a hexadecimal escape sequence, or as '\101' in an octal constant. Similarly, to place a carriage return at the end of a line, the following three methods could be used; however, the first is preferred: "An example of a normal escape: \n" "An example of a hexadecimal escape: \x0D" "An example of an octal escape: \015" When a character escape sequence is used within a string, the actual value of the escape sequence is stored in a string (i.e., only one byte of data per escape). Thus, the string: "\n\x0d\015" is only three bytes long in memory once the program is compiled and assembled. `Language Definition - Data Representation` 2 - 5 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Variable Names The names given to identify variables, functions, macros, and labels are called "identifiers" and all follow the same rules as to their format. C identifiers may be of any length (be practical) and must start with an alphabetic character ['A' through 'Z', 'a' through 'z'] or the underline ['_'], with the rest of the characters in the name consisting of upper-case or lower-case alphabetic characters ['A' through 'Z', 'a' through 'z'], nu- meric characters [0 through 9], or the underline character ['_']. MC keeps all the characters of your identifier as significant; however, if the identifier is to be used as an extern, only the first seven (7) char- acters of an "extern" identifier will be used by the assembler and linker, so these first seven must be unique. Also, the assembler you use may limit the length of symbol names. C is case-sensitive, i.e., recognizes the difference between lower-case and upper-case in identifiers. Thus, "EOF", "eof", and "Eof" are all differ- ent identifiers to C. However, identifiers which must be written out in assembler source code are converted to upper-case, since assemblers, in gen- eral, do not allow lower case assembly language code. A good, simple rule to follow is to use UPPER-case for macro constants only, and lower-case for all other identifiers. Since macro identifiers are not written to the assembly output file, they will not conflict with any other identifiers which are the same, except for case differences. The C language reserves certain "words" which it uses as keywords. These keywords can not be used as identifiers. The list of reserved words is: auto, break, case, char, continue, default, do, double, else, entry, enum, extern, float, for, goto, if, int, long, register, return, short, sizeof, static, struct, switch, typedef, union, unsigned, void, while. `Language Definition - Variables` 2 - 6 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Data Declarations C variables must always be declared before use. The standard procedure is to declare variables at the beginning of the program (globals) and at the beginning of each function (locals). Locals must be declared before any executable statements. MC supports the following variable types and adjec- tives: _____________________________________________________________ | | | `char` - an 8-bit unsigned character | | | | `int` - a 16-bit signed integer | | | | `float` - a 32-bit floating point | | | | `double` - a 64-bit floating point | | | | `struct` - the specifier of a structure | | | | `union` - the specifier of a union | | | | `typedef` - the operand of a typedef | | | | `short` - usually applied to ints but ignored by MC | | | | `long` - used to specify 32-bit integers | | | | `unsigned` - applied to ints or long ints | |_____________________________________________________________| Type char Character variables are stored in eight bits, or a byte. MC always treats a char as unsigned. The declaration: char c, string[81]; establishes a character variable named "c" and a singly dimensioned character array named "string" which can hold a string of maximum length equal to 80 characters. Arrays of one or more dimensions are allowed. Type int [and short int] Integer variables as well as short integer variables are stored in six- teen bits. The short declaration is provided in the interest of portability. Make no assumptions about the storage size of pointers. Although a pointer may be stored in either 16 bits or 32 bits, a pointer is not an int! The declarations: int a; short b; short int b2; are all acceptable declarations, and all result in the same size integer `Language Definition - Data Declarations` 2 - 7 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` field. This is acceptable, since the C language does not guarantee that a "short" will be shorter than integers. Integers declared in this manner are signed, i.e., their most significant bit is regarded as a sign bit. Their values can range from -32,768 to 32,767 (decimal). Unsigned fields do not have a sign bit. They range from 0 to 65,535 (decimal) and are declared like this: unsigned u; unsigned int u2; Type long int Long integer variables are stored in thirty two (32) bits. The declara- tions: long int number; long datasize; are both acceptable declarations, and each results in a 32-bit integer field. Long integers declared in this manner are signed, i.e., their most signifi- cant bit is regarded as a sign bit. The values can range from -2,147,483,648 to 2,147,483,647 (decimal). Unsigned fields do not have a sign bit. They range from 0 to 4,294,967,296 (decimal) and are declared like this: unsigned long lu; unsigned long int lu2; Type float and type double Float and double floating point variables are stored in thirty two (32) and sixty-four (64) bits respectively. The declarations: float fvalue; double dvar; are acceptable declarations; the first results in a 32-bit floating point field and the second results in a 64-bit double precision floating point field. Floating point variables are always signed. Their value varies from approximately -1.7e+38 through +1.7e+38. Floats maintain about 6-7 digits of precision while doubles maintain about 15-16 digits of precision. The only direct operations which may be performed on float and double variables are addition, subtraction, multiplication, division, comparison, logical not, negation, increment, decrement, and address_of. All others are illegal. It is important to note that per the specifications in K&R pertaining to arguments of a function, "C converts all float actual parameters to double, so formal parameters declared float have their declaration adjusted to read double." Type struct structure_tag A structure is a method of collecting one or more variables into one grouping using a single name. Where more than one variable is grouped together, they may be of the same or of different types. The grouping is commonly conceptualized as a "record". A structure template is declared with `Language Definition - Data Declarations` 2 - 8 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` the syntax: struct structure_tag { type_1 member_1; type_2 member_2; type_n member_n; }; The structure_tag is optional and is generally used when many structures will be using that structure template. The closing brace of the structure template may be followed by a variable or list of variables, just like you can do for any of the types noted above (char, int, long, float, double). When no variable follows the closing brace, the structure template remins just a template and no space is reserved for the members. When a variable list does follow the closing brace, adequate storage for all of the structure's members are reserved for each element in that variable list. For example, the following declaration is a structure template which has two members, one of which is an array: struct keyword { char *name; int index[2]; }; The member "name" is declared as a pointer_to_char in this structure decla- ration while the member "index" is an integer array of length two. Since this is only a template, no storage is reserved. The above structure template may be assigned to a structure by another structure declaration such as: struct keyword primary; which declares "primary" to be a type "struct keyword". Where a structure definition is only needed in a single module, it may be declared directly without the structure tag. For example: struct { int hours, minutes, seconds; } clock; declares a structure named "clock" which contains three ints. Each element of the structure is termed a member. A member can only be accessed as part of the structure. For instance, in the "primary" structure defined above, the syntax "primary.name" refers to the member, "name". Like- wise, the second element of the index array member is referenced by the syntax, "primary.index[1]". A variable may be typed as an array of structures (not to be confused with an array member of a structure). Using the struct keyword template illustrated above, we can declare an array of type struct keyword with: struct keyword speech[10]; `Language Definition - Data Declarations` 2 - 9 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` This declares "speech" to be an array of type struct keyword. The syntax for referencing an element of the structure is to bind the structure subscript to the name of the structure. For example, the "name" and "index[0] members of the fifth structure of "speech" would be referenced with: speech[4].name speech[4].index[0] A variable may be declared as a pointer_to_struct. Again following our example, if "ps" is declared via "struct keyword *ps;", then the above mem- bers would be referenced via the syntax: (*ps).name (*ps).index[1] Since the structure dot operator has a higher precedence than the indirection operator, the parentheses are needed. This somewhat kludgy syntax can be re- placed with the structure indirection shorthand using the "->" operator. The structure indirection operator is composed of a minus sign followed by a right angle bracket. The above two references would now be written as: ps->name ps->index[1] A pointer_to_structure can be passed as an argument to a function; a structure cannot! Likewise, a function can return a pointer_to_structure but canot return a structure. Another limitation of structures is that a member of a structure cannot be a structure of the same type (think about that); however, it can be a pointer to its type. This does not restrict members from being other structure types. Type union union_tag A union provides a technique for accessing elements of a record in dif- ferent ways at different times. A union is declared similarly to a structure. Also, you can only access a member or take the address of a union. The members of a union all have a zero offset from the union's origin. The actual amount of memory space assigned is the space required by its largest member. The union declaration is somewhat similar to the EQUIVALENCE statement of FORTRAN. An interesting example of a union is found in the Z80REGS header file. In this union named "REGS", two members are declared - each a structure. One member is the structure named "wordregs" and the other is a structure named "byteregs". The storage space for "byteregs" completely overlaps the storage for "wordregs" thereby providing you with a convenient method of accessing the low-order or high-order register of a 16-bit register pair. This example has a union with two structure members. Alternatively a union could be a member of a structure. Type void The "void" type is used to declare a function which has no return value. It is beneficial to type "void" such functions because an attempt to use the value returned by a void function will be flagged as an error. `Language Definition - Data Declarations` 2 - 10 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Arrays Arrays of one or more dimensions are allowed for short, int, long, unsigned, float, double, or pointer types, as well as for structures and unions. An array is denoted by appending the the dimension enclosed in square brackets to the identifier. For example, arrays of one, two, and three dimensions could be declared like this: char buffer[81]; double grid[25][25]; char bit_plane[8][24][80]; The first defines a character buffer of 81 elements. The second defines a two dimension array of doubles having 625 elements. The third defines bit_plane to be a three dimensional character array - 8 planes of 24 rows by 80 columns. Pointers Pointers may be declared for any data type. Pointer variables are dif- ferent from the types described so far, in that they normally contain the ADDRESS of a data item. For example, char *cp; declares a pointer_to_char variable named "cp". The asterisk denotes INDIRECTION, i.e., that the data item is referred to indirectly through the pointer variable "cp". The address of the data item must be stored in the variable, "cp", before it is used as a pointer to access a data item. To refer to the data itself, an asterisk is placed before the name, e.g., *cp denotes the data item. An example of practical use follows: getit(cp) char *cp; { int c; while ((c=getchar()) != EOL && c != EOF) *cp++ = c; *cp=NULL; return c; } The function, getit(), inputs characters continually from the standard input until end-of-file or end-of-line characters are encountered. When getit() is called, the pointer argument, cp, contains the address of a buffer area. One by one the characters are placed in the buffer, (*cp++ = c), and the buffer pointer is incremented by the post increment operator (++). A simple peek() and poke() set of functions can easily be written using pointers. Witness the following two functions: int peek(s) char *s; { return *s; } void poke(s,c) char *s; int c; { *s = c; } `Language Definition - Data Declarations` 2 - 11 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` When the actual argument to a function is an array, the formal argument declaration in the function may be made in two ways. It may be declared as a pointer or an array without the size in the array declaration. For example, funk(arg1,arg2) int arg1; char arg2[]; declares a character array, "arg2", of an unknown number of elements. This could also have been declared as: funk(arg1,arg2) int arg1; char *arg2; to define arg2 as a pointer to a char. Pointers may be INDEXED to get to the "nth" item in an array. Using the example above, arg2 would contain the address of the beginning of an array of characters. "arg2[0]" denotes the first element in the array, and "arg2[22]" denotes the 23rd element. No matter how a pointer is declared, either method of using the pointer may be employed as the programmer sees fit. Thus, "*arg2" and "arg2[0]" refer to the same data item and may be used interchangeably in the same program. Using "*arg2" is a little more efficient, however. The array declaration without the number of elements within the brackets is allowed only in external declarations and in argument declarations. Sta- tics, globals, and locals declared this way are illegal. Pointers may point to other pointers. This bombshell of a statement is probably too much for you after the last few paragraphs; it must be said, however. C allows pointers to have more than one LEVEL OF INDIRECTION. This can be declared several ways: shine() { char *names[]; char *(*words); . . . . . . . . . . . . Both of these declarations result in the same effect: a pointer which points to a pointer which points to a character field. Pointer variables may have up to 255 levels of indirection. However, the practical limit is the ability of the programmer to keep track of all this. In general, two levels of indirection are all most folks can take. The operations which may be performed on pointers are severely restric- ted. The allowed operations are: (a) Pointer + offset or offset + pointer, offset is scaled. (b) Pointer - offset, offset is scaled. (c) Pointer - pointer, result is scaled. (d) Pointer = expression. (e) ++, --, logical not, ||, &&, and comparisons. `Language Definition - Data Declarations` 2 - 12 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Initialization of Variables C allows you to initialize variables within the declaration statement. For instance, the declarative, int var = 100; declares "var" to be of type "int" with an initial value of 100. A pointer to a string may be declared and initialized with the format, char *pstring = "This is an initialized string pointer"; You may declare a series of variables of the same type as well as their initializations with the format, float f1=1.0, f2=10.0, f3=100.0, f4=1000.0, f5=10000.0; An array can be initialized by placing the initialization values within braces. For example, int table[5] = {1, 10, 100, 1000, 10000}; declares table to be an integer array of dimension 5. Table[0] is initialized to the value 1, table[1] to 10, table[2] to 100, table[3] to 1000, and table[4] to 10000. Structures may also be initialized. For instance, the format, struct { char *name; } dow[5] = {"Mon","Tue","Wed","Thu","Fri"}; defines the array of structures, "dow", consisting of one element, "*name". The array is of dimension 5 with each array element constituting the struc- ture. Each structure element is initialized as a pointer to the corresponding 3-character day name. Thus, "puts(dow[0].name);" would print, "Mon". Note that automatic structures and automatic arrays (these are considered "aggregates" by K&R) may not be initialized. You also cannot initialize a union. `Language Definition - Data Declarations` 2 - 13 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Scope of Variables and Functions Variables or functions which are declared outside of any function, i.e, which are not parameters to functions or declared within braces, are called "external". They are external to all functions. External variables and functions can be accessed only from any of the functions subsequently defined within the module being compiled. They are usually used to create static variables which are to be accessed only by a function or group of functions. However, by using the "extern" statement in a separately compiled module, say module_B, an external variable or function of module_A may be accessed from that separately compiled module_B. Please do not confuse "extern" and external. External variables and functions are declared without the "extern" statement strictly by their position exterior to any function or compound statement. Variables declared within a function are called "local". Functions may not be defined within another function, as is the case with the Pascal lang- uage. However, a function may be DECLARED "extern" so that it may be accessed within the currently defined function. Local variables may not be accessed from any other functions. They only exist for the function in which they are declared. Even within the function, a local variable can only be accessed in the block in which it is declared. Remember, a block is a section of code contained within a matching pair of braces. Local variables can have the same name as external variables, or local variables declared in different blocks. If a local variable has the same name as an external variable then the local variable is the one accessed when used within the local block. In the following example: int same; /* this is an external variable */ funk(same) { return same; /* return local copy */ } hunk() { if (block_1) { int same; /* some code could go here */ } else { char same; /* some other code here */ } } every declaration of "same" was a unique variable. Although legal, the dec- laration of local variables with the same name within the same function is not recommended. This type of trickery, as shown in hunk(), needlessly causes confusion and is easily avoided. `Language Definition - Scope of Variables` 2 - 14 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Storage Classes Variables and functions may be declared as being in certain classes. These classes specify where variables are to be stored. The classes available in C are: auto, static, extern, register, and typedef. The storage class of an object is specified by placing the class name in front of the normal dec- laration: auto char c; static int ai[20][80]; Storage Class - auto Variables which are declared "auto" are stored on the stack. This is the default for variables declared within a function, so the "auto" keyword may therefore be omitted. Local variables which are "auto" are created afresh each time the function in which they are declared is called. This allows functions to be re-entrant and recursive. Functions may not be declared with class "auto" since a function must be declared outside of any other function. As K&R say, the C compiler is incapable of compiling code onto the stack! The scope of an auto variable is the block (within braces) in which it is declared. All other portions of the code being compiled are oblivious to the existence of the auto variable, and in fact there may exist other vari- ables with the same name. The auto class is illegal for functions and other external definitions (any variables declared outside of a function). In terms of speed of access, auto variables are accessed the slowest; thus, if timing is important and your program does not require recursion, use register or static variables. Storage Class - Register Variables declared in the register class are treated similarly to auto variables by MC. The number of register variables permitted depends on the number of extra machine registers available for use. MC makes use of the two index registers of the Z-80 (IX and IY) which can be used for ints and pointers. Register variables are usually accessed faster than autos but not as fast as statics. Any register variables declared in excess of two are stored on the stack in the same manner as an auto and are also illegal out- side of a function; however, each function is permitted up to two register variables. The scope of register variables is the same as that for auto variables. The formal arguments of a function may also be declared register. Note that the "address_of" operator may not be applied to register variables. Storage Class - Extern The "extern" storage class allows an external variable declared in one module to be accessed from another module. A "module" is what is processed by one invocation of MC, i.e., one set of C source input. Let's say that the following declaration: int choice; `Language Definition - Storage Classes` 2 - 15 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` exists in module 1. If module 2 functions need to access this same variable, the declaration: extern int choice; would allow the access needed. C will not reserve any storage for "choice" in module 2, since the storage class, "extern", tells C that storage has been reserved in another module. The programmer MUST ensure that the declarations are compatible between modules. In other words, all "extern" declarations must match the external declaration (declaration without "extern") by having the same type, size, and amount of indirection. Otherwise, C may access the variable in incorrect ways. The extern statement may also be used to declare what a function returns before it is defined in the program. This "forward" declaration allows a function which returns something other than a signed integer to be defined before it is used. If the forward declaration is not given and a function is as-yet-undefined, the compiler assumes that the function returns a signed integer which may be incorrect for many functions. Storage Class - Static Static objects are stored in declared, fixed memory space. Their beha- vior is the same as that of external variables; their scope is more limited, however. Static variables declared outside of a function can only be accessed by functions within the module being compiled. Other (separately compiled) modules cannot get to them by declaring them "extern". Static variables declared outside of all functions are accessible to all functions subse- quently defined within the module. Static variables declared within a func- tion are similar in scope to auto and register variables. They can only be accessed in the block in which they are declared. Thus, two static variables with the same name may be declared in different functions. Functions may also be defined as "static", making them only accessible from within the current module. However, since MC is a one-pass compiler, the definition of a static function must precede any reference to the static function. This is because the compiler assumes that an as-yet-undefined function is an external function. Alternatively, you may use a forward dec- laration. Storage Class - typedef Typedef is provided in the C language not as a unique storage class, but as a means for creating new data type names. Note that typedef does not create new data types, but rather provides a method for giving special names to existing data types. This facility is useful to create customized names which bear some association to the class of objects being typed. For instance, the typedef statement: typedef char *POINTER; declares "POINTER" to be a synonym for the type pointer_to_character. Thus, a statement such as the following can be used to clearly denote the meaning of `Language Definition - Storage Classes` 2 - 16 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` the declarations: POINTER first, last; POINTER table[SIZE]; A typedef is somewhat similar to the preprocessor #define. It performs some textual substitution. It is a little more flexible, though, since the actual substitution can be more complex. It has a great use in enhancing the portability across compilers by introducing a single point definition of a variable type rather than having the actual definition scattered throughout many source modules. Thus, where a declaration type must be changed, it only need be changed in one place (usually in a header file). Storage Class - Defaults When a variable is declared by only stating the storage class: auto x1; register x2; extern x3; static x3; the variable type is assumed to be "int". This is a perfectly acceptable shorthand way to make integer declarations. When the declaration of a local (declared within a function) variable or argument has no storage class, C assumes that the variable is an auto vari- able. A function declared within another function body is assumed to have a storage class of external. The compiler regards the declaration as if an "extern" statement preceded it. External declarations which do not have a storage class declared are special entities. They belong to the implicit class, "external", and may be referenced from other (separately compiled) modules which declare the vari- able as "extern". `Language Definition - Storage Classes` 2 - 17 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Expressions One of the most powerful features of the C language is its expression capabilities. The amount of work that can be done by one expression is some- times mind-boggling. A quick example: (end_of_file = (c=getc(file))==EOF)) ? fclose(file) : ++count ; This convoluted statement will get a character from a file and place it in the variable, "c". The character is compared to the value "EOF" which indicates end of file; the result, true or false, is placed in the variable, "end_of_file". Finally, if it was the end of the file, the file is closed. Otherwise, a counter variable, "count", is incremented to provide a count of the characters read. The example was a bit exaggerated, and expressions this complex can be quite hard to understand. Two statements must be made about the complexity of expressions in the C language. The programmer who does not fully know and use C's expression capabilities is seriously handicapped, unable to use the full power of the C language. On the other hand, a quotation from THE ELEMENTS OF PROGRAMMING STYLE by Kernighan and Plaugher is appropriate: "Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?" The word "maintain" could be substituted for "debug" in the quote above, and it would still be valid. You must be able to understand later what you wrote into your program. If others are going to have to maintain your pro- gram, the principle of KISS (Keep It Simple, Stupid) should prevail. This is not intended to discourage the use of complex expressions. Just keep in mind that the more operators involved in an expression, the more difficult it is to properly place parentheses and keep the precedence of operators straight. There are two kinds of expressions in many computer languages: logical expressions and arithmetic expressions. Logical expressions are usually for comparing things and for making choices. The result of a logical expression is either true or false. Arithmetic expressions result in a number. Usually an assignment to a variable is made to save the result of the arithmetic ex- pression, or it is passed as an argument. In many language implementations, only one type of expression may be used in certain contexts. For instance, the BASIC program statement: 1000 A = ( C <= B ) attempts to assign to A the result of the comparison C to B. This is not allowed in many implementations because they are expecting an arithmetic assignment. Even if some BASIC's allow it, it is best not to do this type of assignment, in order to keep programs relatively portable. `Language Definition - Expressions` 2 - 18 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Another situation is shown in PASCAL: IF A := (B < C) THEN BEGIN where the PASCAL compiler expects a boolean expression between IF and THEN. Even if A is a boolean variable this assignment is not allowed in most PASCAL compilers. This is not intended to denegrate PASCAL. There are good reasons why the authors of PASCAL did things this way. However, the C language does not draw distinctions between types of expressions within the context of the program. The distinctions are made in the types of operators instead. Primary Expressions The elements which are manipulated by operators in an expression are called primary expressions. The basic elements which make up a primary ex- pression are identifiers, constants, and strings. Identifiers are the names of variables and functions. Function and array identifiers effectively re- solve to the address of the function or array, while all other variable identifiers resolve to the contents of the variable. Constants are character or numeric (decimal, hex, octal) values. Strings resolve to a character pointer which points to the first character of the string. The operators which C provides for stating primary expressions group left to right. This means that the left-most operator is interpreted first. The five primary operators supplied by C are: isolating parentheses, sub- scripting, function invocation, structure/union ARROW, and structure/union DOT. _____________________________________________________________ | | | (expression) isolating parentheses | | | | p_ex [expression] subscripting | | | | p_ex (expression_list) function invocation | | | | . DOT obtains member of structure/union | | | | -> ARROW obtains member indirectly through | | structure/union pointer | | | | Note: "p_ex" stands for "primary_expression" | |_____________________________________________________________| Isolating Parentheses When the order in which an expression is to be evaluated conflicts with the precedence of operators, the isolating parentheses provide a way around the conflict. The expression within parentheses is evaluated first, before the result of the enclosed expression is used in any expression outside the parentheses. For example, when predicting the percentage of up-time for any equipment, the following formula is used: `Language Definition - Expressions` 2 - 19 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` MTBF availability = ------------- MTBF + MTTR MTBF = mean time between failures MTTR = mean time to repair When writing this formula into a C expression a conflict occurs because the division operator takes precedence over the addition operator. If the ex- pression is written like this: up_time = mtbf / mtbf + mttr the result will always be mttr plus one. This is because the division is done before the addition. To avoid this, the expression can be stated as follows: up_time = mtbf / (mtbf + mttr) to achieve the correct result. Parentheses can be used on either side of an assignment operator. At the risk of confusing the reader with as-yet undefined operators, we nevertheless provide an example using pointers. In certain cases during the use of pointer arrays, indirection must be performed before subscripting into the data item. Since subscripting takes precedence over indirection, this kind of expression must be written as follows: example(arg) char *arg[]; /* pointer to a char pointer array */ { /* wrong way - accesses third pointer */ /* instead of third character. */ *arg[3] = 0 ; /* right way - zero's the third character of */ /* first string */ (*arg)[3] = 0 ; } Subscripting Subscripting is denoted by a subscript in brackets following a primary expression: primary_expression [subscript] primary_expression [subscript_1][subscript_2] If the primary expression is an array name, or a pointer to an array, the subscripted expression returns the element denoted by the value of the sub- script. C arrays are subscripted from zero, i.e, the first element in an array is numbered zero. If more than one dimension is specified, the storage of array elements is such that the rightmost subscript varies fastest as elements are accessed in storage order. `Language Definition - Expressions` 2 - 20 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Function identifiers may not be subscripted. A primary expression deno- ting an array of pointers to functions may be subscripted. The primary expression must indicate the size of the object being subscripted (char, int, pointer) or the subscript will produce an error message. For example: x = 25[3]; is invalid. Function Invocation A primary expression followed by parentheses will cause the function denoted by the primary expression to be called. Arguments may be passed to the invoked function by placing them in the parentheses, separated by comma's. Any number of arguments can be passed to the called function. Care must be taken that the number of arguments passed is the number that the function expects. Otherwise unpredictable behavior may result (certainly not correct behavior). If a variable number of parameters must be passed, then a control indicator must be passed to tell the called function how many arguments there are (for example, the fprintf() and printf() functions in the standard library). Arguments can be any valid C expression, including other function calls. The arguments are evaluated from right to left, i.e., the right-most expression is evaluated first. The programmer should not rely on this order of evaluation since some other implementations of the C language evaluate them left to right. Statements like this one: funk( arg++, arg2[arg] ); will cause different elements of arg2 to be passed to funk() when different C compilers are used. Stay away from this sort of trickery if you can. . DOT [designate member of structure/union] The structure/union dot operator is used to specify a member of a structure or union. Thus, if there exists for example, a structure of the name "time" which has members named "hour", "minutes", and "seconds", then the constructs "time.hour", "time.minutes", and "time.seconds" refer to the member objects when used in an expression. Other details concerning struc- tures and unions are provided in the section on data declarations. -> ARROW [designate member through structure/union pointer] This structure/union operator is used when you have a pointer to a structure or union and you wish to reference one of its members. For example, if the identifier "pt" has been declared a pointer to the time structure noted above, then the constructs, "pt->hour", "pt->minutes", and "pt->sec- onds" reference the objects within the structure. The construct of "structure or union pointer -> membername" is eqivalent to "(* structure or union pointer).membername" and is essentially a shorthand method of using the indirection operator. `Language Definition - Expressions` 2 - 21 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Unary Operators Unary operators operate on one object (hence the name). If more than one unary operator operates on the same object, the operators are evaluated right to left. The unary operators supplied by C are: _____________________________________________________________ | | | OPERATOR OBJECT DESCRIPTION | | -------- ---------- --------------------------------- | | | | * expression indirection; means "object at..." | | | | & lvalue pointer; means "address of..." | | | | - expression negates the expression; | | "minus expression" | | | | ! expression logical complement; | | "not expression" | | | | ~ expression one's complement of expression | | | | ++ lvalue increment and save in lvalue | | | | -- lvalue decrement and save in lvalue | | | | (typename) expression cast the result to "typename" | | | | sizeof expression obtain the size of the result of | | expression in "bytes" | | | | sizeof (typename) obtain the size of "typename" | | in bytes | |_____________________________________________________________| All unary operators must appear before (prefix) the object, except the increment and decrement operators which may appear after (postfix) the ob- ject. The term "lvalue" means an expression which evaluates to the address of a data element or pointer field. Constants, function identifiers, and array names are not lvalues. The term derives from the observation that "lvalues" are the only expressions allowed on the left side of an assignment expression. '*' [asterisk - object at] The indirection operator can only operate on a pointer expression. Its meaning is effectively "object at ..." The address contained in the pointer is the address of the object referred to by this type of expression. For example, `Language Definition - Unary Operators` 2 - 22 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` see_pointer (pointer) char *pointer; /* a character pointer */ { /* first print the address passed in pointer */ printf("address is: %u ",pointer); /* now print the data at that address */ printf("data is: %u ", *pointer); } will print both the address (contents of the pointer variable) and the data at that address (result of the indirect expression). '&' [ampersand - address of] This unary operator effectively means "address of..." or "pointer to...". It evaluates to the address of the lvalue it precedes. '-' [minus sign - negation] When the unary negation operator precedes an expression, the result is the two's complement negative of the value of the expression. When the '-' precedes an unsigned or pointer expression, the one's complement of the value is taken. '!' [exclamation point - logical NOT]] The unary logical complement operator, or "not" operator evaluates to FALSE if the expression is true and to TRUE if the expression is false. FALSE is defined as 0 and any non-zero value is considered to be TRUE. However, all C operators which result in TRUE or FALSE produce one (1) as the value for TRUE. Thus, the least significant bit of the result indicates TRUE or FALSE. '~' [tilde - bitwise complement] The one's complement operator inverts every bit in the expression. No regard is given to the type of the expression. '++', '--' [increment, decrement] The increment and decrement operators may be used either before (prefix) the operand or after (postfix) the operand. The operand must be an lvalue or lvalue expression. In either case the contents of the lvalue is incremented or decremented and stored back into the lvalue. The difference between prefix and postfix is how the result of the expression is produced. Prefix means that the value after the increment or decrement is the result of the expres- sion. Postfix means that the value returned by the expression is the value before the increment or decrement. (typename) [type casts] The "(typename) expression" is used to explicitly force the result of "expression" to be converted to the type specified by the cast. Casts are used when the variable or expression result type does not agree with what may be needed for continued evaluation. For instance, to take the log of an integer number, it is necessary to convert it to a double. Thus, the state- `Language Definition - Unary Operators` 2 - 23 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ment: dvalue = log( (double) number); converts the value of the integer "number" to a double before placing it on the stack as the argument to the log function. Note that "number" is not it- self changed, but rather the value is typed to conform to the cast. A cast is similar to the verbs: CDBL, CSNG, CINT commonly found in the BASIC language. sizeof [obtain size of operand in bytes] It is sometimes useful to be able to use the size of an object in an evaluation without actually knowing the physical size of the storage provided for the object. For instance, since the actual size in storage units of an int may vary from machine to machine, the programmer may need to compute a figure irrespective of the storage element size. The "sizeof" operator pro- vides this facility. Since all sizes are known to the compiler at compile time, "sizeof object" may be used in the same way as a constant. For in- stance, the statements: int array[100]; bytes = sizeof array; assigns to "bytes", the actual quantity of storage elements occupied by "array". "Sizeof" may also be used in the format, "sizeof(typename)". Thus, sizeof(int) and sizeof(long) are valid operations. There is significant use of the sizeof operator in calculating the size of a structure. Given the structure, struct functions {  char *name;  double (*func)(); }builtins[] = {  "sin", sin,  "cos", cos,  "tan", tan,  "asin", asin,  "acos", acos,  "atan", atan,  "exp", exp,  "log", log,  0, 0 }; the number of structure entries is simply sizeof builtins / sizeof (struct functions) `Language Definition - Unary Operators` 2 - 24 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Binary Operators Binary operators act upon two expressions together. The type of the result depends on the type of the two expressions. If both types are not identical, the lower type will be promoted to the higher type. The order from lower to higher is: char, int, unsigned int, long, unsigned long, float, double. When the operator is addition or subtraction, if only one expression is a pointer, the result of the expression is a pointer of the same type; if both expressions are pointers, the result is unsigned. These "usual arith- metic conversions" are documented in K&R page 184 (section 6.6) and are reproduced here for convenience: "First, any operands of type char or short are converted to int, and any of type float are converted to double. Then, if either operand is double, the other is converted to double and that is the type of the result. Otherwise, if either operator is long, the other operand is converted to long and that is the type of the result. Otherwise, if either operator is unsigned, the other operand is converted to unsigned and that is the type of the result. Else, both operands must be int, and that is the type of the result." When several binary expressions are concatenated together (without isolating parentheses) the order in which the binary expressions are eval- uated depends on the precedence of the operators in the expression. In the expression, a + b * c the evaluation of "b * c" precedes the evaluation of the addition, since multiplication has a higher precedence than addition. The expression is evaluated like this: a + (b * c) As previously described, isolating parentheses can be used to change the order of evaluation. To have the addition performed first, the expression can be written: (a + b) * c Each class of operands is described below in order from the highest precedence to the lowest. When all the operators in a complex expression have the same level of precedence they are evaluated in a certain order; right to left or left to right. It can be said that a class of operators "group" left to right, or right to left. If the order of evaluation between like operators does not matter, the operator is said to be associative. Here is an example of how the order of evaluation affects an expression: a / b / c / d The division operator is said to group "left to right"; thus, this expression is evaluated a follows: (((a / b) / c) / d) `Language Definition - Binary Operators` 2 - 25 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ___________________________________________________________ | | | PRECEDENCE OF BINARY OPERATORS | | (Highest to lowest) | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | MULTIPLICATIVE OPERATORS - group left to right | | expression * expression multiplication | | expression / expression division | | expression % expression modulus (remainder) | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | ADDITIVE OPERATORS - group left to right | | expression + expression addition | | expression - expression subtraction | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | SHIFT OPERATORS - group left to right | | expression << expression shift left | | expression >> expression shift right | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | RELATIONAL OPERATORS - group left to right | | expression < expression less than | | expression > expression greater than | | expression <= expression less than or equal to | | expression >= expression greater than or equal to | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | EQUALITY OPERATORS - group left to right | | expression == expression equal to | | expression != expression not equal to | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | BITWISE AND OPERATOR - associative | | expression & expression bitwise and | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | BITWISE EXCLUSIVE OR OPERATOR - associative | | expression ^ expression bitwise exclusive or | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | BITWISE INCLUSIVE OR OPERATOR - associative | | expression | expression bitwise inclusive or | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | LOGICAL AND OPERATOR - groups left to right | | expression && expression logical and | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | LOGICAL OR OPERATOR - groups left to right | | expression || expression logical or | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | CONDITIONAL OPERATOR - groups right to left | | expression ? expression : expression | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | ASSIGNMENT OPERATORS - group right to left | | lvalue = expression simple assignment | | lvalue = expression compound assignment | | ( is any binary operator except logical, | | relational, or conditional operators) | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | COMMA OPERATOR - groups left to right | | expression , expression pair of expressions | |___________________________________________________________| `Language Definition - Binary Operators` 2 - 26 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` '*', '/', '%' [multiplication, division, modulus] The multiplicative operators take precedence over all other binary operators and group left to right. When the result of integer multiplication overflows an int, or when the result of long integer multiplication overflows a long, the left-most (high-order) bits are truncated. Since integer division is used, the fractional portion of the result is lost. The result of division is always truncated toward zero. The modulus operator returns the value of the remainder in the integer division of the two expressions. Overflow and underflow floating point errors may be trapped in software by the use of a _fltvec() error trap. This is documented in Chapter 5, "Advanced Topics". '+', '-' [addition, subtraction] The additive operators result in the addition or subtraction of the two expressions. In subtraction, unsigned subtraction only takes place when both expressions are unsigned. If one of the expressions is a pointer and the other is not, the other value is adjusted to reflect the size of the object pointed to. Thus, if "p" is a pointer, "p + 3" returns the address of the fourth object pointed to by "p". If p points to integers, then C automati- cally doubles the offset to account for the two-byte elements. Likewise, if p points to long integers or to doubles, the offset is appropriately adjusted to account for the size of the object. '<<', '>>' [shift_left, shift_right] The shift operators shift the left-hand expression by the number of bits indicated in the right-hand expression. Zeroes are shifted in to replace the bits shifted out. The right-hand expression is always considered unsigned; thus a negative integer will be interpreted as a large unsigned integer. If the right hand expression has a zero value, no shifting takes place. If the right-hand expression contains a value which is larger than the size of the left hand object, the result is always zero. The shift operator is a logical shift, not an arithmetic shift as in some other C implementations. Thus shifting a signed value will not preserve the sign if the shifted value is negative. '<', '>', '<=', '>=' [less, greater, less_or_equal, greater_or_equal] Relational operators result in a TRUE (1) or FALSE (0) value, depending on the indicated condition. '==', '!=' [equal_to, not_equal_to] The equality operators, "equal" and "not equal", respectively also return TRUE (1) or FALSE (0) depending on the two expressions' equality. '&' [bitwise AND] The bitwise AND operator does a bitwise AND with the two expressions. Each bit position in the result will be set to be one if and only if both corresponding bits in the expressions are equal to one. This is useful for isolating individual bits within a word by using a "mask" as one of the expressions. Any bit in the mask which is set to zero will cause that bit in `Language Definition - Binary Operators` 2 - 27 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` the result to be zero. Any bit set to one will cause the bit in the other expression to remain the same. '^' [bitwise XOR] The bitwise exclusive OR operator. Each bit in the result of an exclu- sive OR is set only if the corresponding bits in the expressions are oppo- site, i.e., 1 and 0, or 0 and 1. If they are the same, that bit in the result will be zero. This can be used to complement bits, using a "mask" expression. Any bit which is 1 in the mask will cause the corresponding bit of the other expression to be complemented in the result. Any mask bit which is 0 will pass the corresponding bit unchanged into the result. '|' [bitwise OR] The bitwise inclusive OR operator. Each bit in the result will be set to 1 if either of the corresponding bits in the expressions are equal to 1. This can be used to set any particular bit in an expression to one by using a "mask" expression. If a bit in the mask is equal to 1, then the corresponding bit in the result will be set to 1. If a bit in the mask is equal to 0, then that bit in the result will be the same as in the expression being manipu- lated. '&&' [logical AND] The logical AND operator results in a TRUE (one) or FALSE (zero) con- dition, depending on the relationship of the two expressions. The result is TRUE only if both expressions are true (non-zero). Moreover, if the first expression is FALSE, the second is never evaluated. '||' [logical OR] The logical OR operator returns a TRUE (1) result if either of the ex- pressions is true (non-zero). If the first expression is true, the second expression is not evaluated. '? :' [conditional] The conditional operator gives the C expression repertoire the equiva- lent of an if-then-else construct. It can technically be classified as a binary operator since only one of the last two expressions is evaluated. The first expression is evaluated as true (non-zero) or false (zero). Then, if the first expression was true (non-zero), the second expression is evaluated as the result of the expression. Otherwise, if the first expression was false (zero), the third expression is evaluated for the result. The conditional operator groups right to left: a ? b : c ? d ? e : f : g is evaluated in the following manner: a ? b : (c ? (d ? e : f) : g) Either or both of the second and third expressions can contain conditional expressions. `Language Definition - Binary Operators` 2 - 28 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` '=' [assignment] The simple assignment, '=', places the result of the right-hand expres- sion unchanged into the object denoted by the left-hand expression. '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '&=', '^=', '|=' [assignment] The compound assignment operators place the result of the right-hand expression into the object denoted by the left-hand expression, after per- forming the indicated operation with the contents of the lvalue when an assignment operator other than '=' is used. The result is the value stored into the left hand object. The compound assignment operators have the form: expression_1 = expression_2 and is evaluated like this expression: expression_1 = expression_1 expression_2 The first form is more efficient since expression_1 only needs to be eval- uated once. , [comma] The comma operator sets off a pair of expressions which are evaluated left to right. Both the type and value of the result are the type and value of the rightmost operand; thus, the values of the left operands are dis- carded. The comma operator usually finds use in a "for" statement to initialize more than one quantity. `Language Definition - Binary Operators` 2 - 29 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` C Statements C statements are used to specify the action to be taken by the program. The statements given in the program are normally executed one after the other. Certain statements (conditional and looping statements) will direct the order of and conditions for execution of other statements. Some defini- tions of statements in the following text require that a substatement be included in the statement. Any place where a substatement is required, there may be one simple statement, or more than one statement combined in a com- pound statement. Simple Statements Simple statements are of three types: expression, declarative, and con- trol. The declarative statements are described fully in the previous sections on functions and variables. The type, size and scope of functions and vari- ables are declared in declarative statements. A simple statement always ends with a semicolon. The semicolon is the STATEMENT TERMINATOR. It is not a statement separator as in the PASCAL lan- guage. It is always required at the end of a simple statement. Compound Statements The left and right brace characters, "{"and "}", are used to indicate the beginning and end (respectively) of a compound statement. A compound statement, also called a block, can be used anywhere that a simple statement may be used. Thus, wherever C's syntax requires a statement, more than one statement may be given by enclosing them in braces. Within the compound statement there may be any combination of simple and compound statements. The compound statement has the format: { } No declarations or statements are required, although an empty block could be used as a null statement. The declarations must appear before any executable statements. Any of the statements may in turn be another compound statement. No semicolon is required after the compound statement. The only place where a compound statement is required instead of a simple statement is in the body of the switch-case statement. The body of a function is one compound statement. Here are some examples of compound statements: func() { /* the body compound statement */ a=b; /* simple statement */ if (a>c) { /* another compound statement */ c=a; b=a; } /* end of compound statement */ return a+b+c; } /* end of function body compound statement */ `Language Definition - Statements` 2 - 30 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Null Statement A null statement is sort of a place-holder. C requires that a statement be given in certain places. If no action is needed in the place required then the null statement can be used. No action is taken by the null statement. The null statement is simply a statement terminator (semicolon) by itself, with no preceding statement. null() { /* do-nothing function */ ; /* a null statement */ } Expression Statement A C expression followed by a semicolon is called an expression state- ment. The expression is performed when it is encountered. C will allow an expression that has no assignment in an expression statement, even if it does nothing. Expression statements are used to assign values to or modify values of variables, or to invoke functions. Some sample uses of expression state- ments: retcode = call_function() ; /* call a function */ a = b = c = 0 ; /* make a, b, c equal to 0 */ ++counter ; /* increment a counter */ If Statement _________________________________________ | | | `if (expression) statement` | | | | `if (expression) statement` | | `else statement | |_________________________________________| The "if" statement gives the programmer the capability to decide whether a statement will be executed. The criterion for the decision is the result of evaluating the expression. The expression may be any valid C expression. If the expression evaluates to TRUE (non-zero), then the statement is executed. If the expression evaluates to FALSE (zero), then the statement following the "else" (if any) is executed. "If" statements may be nested, i.e., the statement within an "if" statement may be another "if" statement. Too much nesting of "if" statements can be hard to follow, so moderation is advised. Unless clearly established otherwise by the use of braces, an "else" will bind to the closest previous "if". Some examples of "if" statements: if (x < 0) x = -x ; /* absolute value of x */ `Language Definition - Statements` 2 - 31 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` if (i<=0) { i=x; b=a; } /* compound statement */ else --i; /* and an else clause */ if (past_twelve) /* nested if statements */ if (before_six) say("good afternoon"); else say("good evening"); else say("good morning"); Switch-Case Statement _____________________________________________________________ | | | `switch (expression) { ... }` | | | | `switch_statement = statement` | | `case constant_expression :` | | `default :` | |_____________________________________________________________| The switch-case statement allows program execution within the to be determined by the "case" and "default" prefixes. The expression in the switch statement is evaluated first and converted to a short integer. Then, if any statements precede the first prefix, they are executed. Finally, if any of the constant_expressions match the result of the switch expression, execution continues immediately past that "case" prefix. If none of the cases match the result and there is a "default" prefix, then execution continues at the "default" prefix. Execution will continue from then on until either the end of the switch-case statement is reached or until a "break" statement is encountered. Otherwise, when no matching case is found, no further statements in the switch_statement are executed. The switch-case statement MUST have a compound statement as its sub- statement. This is the only case where this is true. The "default" and "case" statements may occur in any order within the body of the switch-case. Local declarations are acceptable preceding the first prefix or statement. The "break" statement is used to exit the switch_case statement. switch (month) { case january: case october: case december: case july: case august: case march: case may: days = 31; break; case september: case april: case june: case november: days = 30; break; case february: days = leap_year ? 29 : 28; break; default: days = 0; error = true; } `Language Definition - Statements` 2 - 32 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` While Statement _________________________________________ | | | `while (expression) statement;` | |_________________________________________| The most basic form of looping is provided in C by the "while" state- ment. Simply stated, while the expression results in a TRUE (non-zero) value, "statement" (also called substatement) is executed. The expression is re-evaluated before each time the substatement is executed. Therefore, the substatement may be executed from zero to any number of times depending on the expression's current value. If more than one simple statement must be placed in the loop substate- ment, then the substatement must be a compound statement. The "break" state- ment can be used to exit the loop from within the statement. The "continue" statement can be used to continue directly on to re-evaluate the test expression, skipping the rest of the substatement, from anywhere within the statement. while (driving) watch(the_road); while (jogging) { take(a_step); breathe(); if (too_tired) break; } Do Statement _________________________________________ | | | `do statement while (expression) ;` | |_________________________________________| "Do" differs in only one way from the "while" statement - the expression is re-evaluated after the statement is executed. Therefore the substatement will always be executed at least once. The substatement will be repeatedly executed until the expression evaluates to FALSE. do anything(); while (there_is_still_time) ; /* shuffle routine */ do { cut_the_cards(); shuffle(); } while ( ! ready_to_deal ) ; `Language Definition - Statements` 2 - 33 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` For Statement _________________________________________ | | | `for (expr_1;expr_2;expr_3) statement` | |_________________________________________| The "for" statement is a looping statement which provides a convenient place for initializing, testing, and incrementing loop control variables. The format shown above can be rewritten using the while statement: expr_1 ; while ( expr_2 ) { statement expr_3 ; } Expr_1 is evaluated once before the loop is entered. The test expres- sion, expr_2, is re-evaluated before each execution of the substatement. If it results in a FALSE (zero) value, the loop is not executed and execution continues to the next statement. Expr_3 is re-evaluated after each time the substatement is executed. Both expr_1 and expr_3 can be more than one expression, separated by commas. Expr_2 can only be one expression and should result in a logical TRUE or FALSE value. Note that all three expressions may be omitted. If expr_2 is omitted, the test is always TRUE. for ( c = 'A' ; c <= 'Z' ; ++c ) putchar(c); /* print the letter */ /* "Now I've said my ABC's ..." */ Break Statement _________________________________________ | | | `break;` | |_________________________________________| "Break" is used to exit any "while", "do", or "for" loop and to exit the body of a switch-case statement. Whenever a "break" statement is encountered, execution immediately goes to the next statement past the loop or switch-case statement. "Break" is ignored outside of any loop or switch-case compound substatement. For an example of the use of "break" in a switch statement, see the section on switch-case above. strscan(c,s) char c,*s; { /* find character c in string s */ while (*s != c) { if (*s == NULL) break ; /* end of string */ ++s ; /* next character */ } return s ; } `Language Definition - Statements` 2 - 34 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Continue Statement _________________________________________ | | | `continue;` | |_________________________________________| The "continue" statement is used to skip the remaining statements in a compound loop substatement. In a "while" or "do" statement, execution con- tinues at the test expression re-evaluation. In a "for" statement, execution continues at the reinitializing expression (the third expression). The "con- tinue" statement is ignored outside of any loop statement. /* convert to lower case */ while ((c = getchar()) != EOF) { if ( c < 'A' || c > 'Z' ) /* not an uppercase character */ continue ; /* doesn't apply */ c = tolower(c) ; putchar(c) ; } Return Statement _________________________________________ | | | `return;` | | `return expression;` | |_________________________________________| The "return" statement causes the currently executing function to end. If an expression is provided, then the result of the expression is returned as the value of the function. The returned value is undefined if no expres- sion is provided in the "return" statement. The "return" statement is not required in order to effect a return from a function. When no statements are left (the bottom of the function body is reached), the function automatically returns as if a "return" statement with no expression were encountered. A "return" statement is needed when a value must be returned or when the return must take place before the end of the function. The result is automatically converted to the function type, if necessary. square (num) /* square a number */ { return num * num ; } getline(buf) char buf[] ; /* line input buffer */ { /* check for a valid file pointer */ if (file_pointer == NULL) { buf[0] = '\0' ; /* put a null string in buf */ return ; /* back to caller */ } fgets(buf, bufsize, file_pointer); } `Language Definition - Statements` 2 - 35 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Goto Statement _________________________________________ | | | `goto label;` | |_________________________________________| The "goto" statement causes an unconditional branch to the statement identified by label. The labeled statement must be contained in the current function. It is illegal to attempt a "goto" to a statement in some other function. An attempt to do so will probably result in an error during the assembly phase. The following example illustrates the use of "goto" (note: it is strongly recommended that you avoid the use of the "goto" statement): rest(time) int time; { if ( time > 2300 ) goto sleep; else return; sleep: for ( ; ; ) ; } Labeled Statement _________________________________________ | | | `label: statement;` | |_________________________________________| Any executable statement can be prefixed with a label. This construction is usually used to target the argument of a "goto" statement. The format of a label is a valid identifier followed by a colon. The following are labeled statements: calculate: i += 10; bigblock: i = j = k = l = m = n = o = p = 0; `Language Definition - Statements` 2 - 36 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` C Preprocessor Part of the MC compiler is a preprocessor which provides for macro sub- stitution, conditional compilation, inclusion of additional files, and line number control. The features provided in the preprocessor extend the power of the C language by (1) controlling the flow of C source through the compila- tion process; (2) permitting powerful macro substitution of textual strings; and (3) offering string replacement making your program not only more read- able, but easier to maintain, as well. Some of the work performed by the preprocessor has to do with massaging the source text. In this capacity, the preprocessor provides you with the following features: Input lines may be terminated with a backslash "\" for continuation; this is most useful for complex expressions, function calls, and macro definitions which may take more than one line of input for their declaration. Constructions of the form "string_1""string_2" are replaced with "string_1string_2". This allows substitution of macros within strings, if the macro itself is defined as a string. Restriction: the whitespace separating the strings may include an escaped (backslashed) newline but not a bare newline. Un-needed whitespace (spaces, tabs, new-lines, comments) is automatically removed; thus you have complete freedom in inserting whitespace throughout your source code for the purpose of readability. A source text communicates to the preprocessor via directives that con- trol various aspects of the compiler during the compilation process. One of these directives, "#include filespec", you will quickly become familiar with. All preprocessor directives begin with a number-sign character, "#". The directives supported by the MC preprocessor are: _________________________________________ | | | #define identifier text | | #define identifier(parmlist) text | | #undef identifier | | #if constant_expression | | #ifdef identifier | | #ifndef identifier | | #else | | #endif | | #include filespec | |_________________________________________| `Language Definition - C Preprocessor` 2 - 37 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` In addition to the preprocessor directives, there also are others which are used in the compilation and assembly processes. The following directives are passed through the preprocessor to downstream processes: _________________________________________ | | | #option identifier value | | #asm | | #endasm | | #line linenumber filespec | |_________________________________________| Simple Symbolic Substitution [#define] The "#define" directive is a macro definition. It's syntax is: _____________________________________________________________ | | | `#define macname text` | | | | macname - is the symbolic name to be assigned to the | | text replacement string. | | | | text - is the text to replace "macname" throughout | | the C source file. | |_____________________________________________________________| Description The "#define" directive is a macro definition. It creates a macro iden- tifier called "macname", which is defined to be the string of characters following the "macname" (the "text"). Macro identifiers may have any length (1 - n characters), and any number of macros may be defined, subject to mem- ory availability. Macro text replacement may be nested to a depth of 20 which means that a macro definition may itself invoke a macro, etc. Macros may also be redefined at will. Macros may be defined in any order, even if they depend on each other; this is because preprocessor command lines are not themselves preprocessed. However, note that circular definitions will cause a fatal error. The preprocessor will substitute the "text" string wherever "macname" is found in the C source stream except where "macname" appears within single or double quotes. For example, given a definition of the form #define DRAW 1 there would not be a substitution in the statement, 'puts("DRAW ME A BATH");' but there would be in the statement, 'box(DRAW,x1,y1,x2,y2);'. It is recom- mended that macro "macnames" be defined in upper-case characters so that they become distinct when looking at your source code. The "macname" must be a valid C identifier following all the rules of naming identifiers, whereas the "text" is anything and everything up to end of the logical input line. The "text" is substituted until "macname" is `Language Definition - C Preprocessor` 2 - 38 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` redefined via another "#define" or undefined via the "#undef" directive. The macro "dos" is predefined. One of the macros dos5 or dos6 will be predefined based on the DOS under which MC is running. These macros have no replacement text. The macro "__DATE__", when invoked, is replaced with a QUOTED STRING of the asctime() format "Tue Oct 22 10:03:10 1985\n\0", the date and time being retrieved from the system when MC is invoked. The macro "__FILE__", when invoked, is replaced with a QUOTED STRING containing the name of the input file currently being read. The macro "__LINE__", when invoked, is replaced with the number of the source line currently being processed, in decimal. It is NOT a quoted string. Example #include stdio.h #define PRINTX printf("%d\n",x) main() { int x; x = -3 + 4 * 5 - 6; PRINTX; x = 3 + 4 % 5 - 6; PRINTX; } Parameterized Macro Substitution [#define] This powerful directive provides textual substitution with the capabil- ity of specifying substitution parameters in a parameter list which may be different for each macro invocation. _____________________________________________________________ | | | `#define macname(parmlist) text` | | | | macname - is the symbolic name to be assigned to the | | text replacement string. | | | | parmlist - is zero or more parameters of the macro. | | | | text - is the text to replace "macname" throughout | | the C source file. | |_____________________________________________________________| Description Macro definitions may also be written to include dummy parameters which will be substituted with actual parameters when the macro is expanded. This type of definition requires that there not be any white space between the "macname" and the opening parenthesis "(". The actual parameters are desig- nated when the macro is expanded. The preprocessor will substitute the "text" string and the actual parameters passed in the macro call wherever "macname" is found in the C source stream except where it appears within parentheses. `Language Definition - C Preprocessor` 2 - 39 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` For instance, a macro definition of the library function putchar() may be written as #define putchar(byte) putc(byte,stdout) Thereafter, any C statement of "putchar(c)" will be replaced with the state- ment, "putc(c,stdout)". Notice that the actual argument, "c", replaces the dummy parameter, "byte", in the macro definition when the macro is expanded. It is also not necessary for the macro dummy parameter name to be unique across different macros, although it is recommended that it be distinct for the purpose of clarity. A parameterized macro may have up to 128 parameters - more than you would ever have need for. Macro text replacement may be nested to a depth of 20 which means that a macro definition may itself invoke a macro, etc. Macro identifiers may have any length (1 - n characters), and any number of macros may be defined, subject to memory availability. Macros may also be redefined at will. In a macro call, commas are used to separate actual parameters, but are ignored within set(s) of balanced parentheses; a backslash may be used to escape an imbedded comma or unbalanced parenthesis within an actual para- meter. Macros may be defined in any order, even if they depend on each other; this is because preprocessor command lines are not themselves preprocessed. However, note that circular definitions will cause a fatal error. Parameters in the definition portion of a parameterized macro are always replaced, even if they occur within a double-quoted string. Note that this can get tricky. For example, in the following series of parameterized macro definitions, when the string, "PR(cos(d))" is detected, the "x" parameter is the string, "cos(d)" resulting in the substituted statement, printf("cos(d) = %g\t",cos(d)) When a parameterized macro is called with one or more actual arguments missing, the missing arguments will be interpreted as if they were null strings. Note that you must still provide any comma(s) needed to specify all of the parameter positions. For instance, the macro "#define test(a,b) a b" called with the various arguments produces the following results: test(123,456) 123 456 test(abc,) abc test(,xyz) xyz test() Fatal preprocessor error - missing parameters Examples #define PR(x) printf("x = %g\t",x) #define NL putchar('\n') #define PRINT1(x1) PR(x1); NL #define PRINT2(x1,x2) PR(x1); PRINT1(x2) `Language Definition - C Preprocessor` 2 - 40 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Forgetting a Macro Name [#undef] This directive will cause the preprocessor to forget the operand name. _____________________________________________________________ | | | `#undef macname` | | | | macname - is the symbolic name to be "forgotten". | |_____________________________________________________________| Description The "#undef" directive is used to cause the preprocessor to forget the definition of "macname". Thus, after a macro name has been forgotten, no text substitution will be performed if that "macname" is encountered in the C source code. Also, the result of an "#ifdef macname" referencing that macname identifier will be a FALSE state. Example #ifdef DEBUG #undef BRIEF #endif Conditional IF Evaluation [#if] The conditional "#if expression" is used for conditional compilation based on the result of an expression. _____________________________________________________________ | | | `#if constant_expression` | | | | expression - is a simple or complex expression of the | | form permitted in the C language which will | | evaluate to a constant. | |_____________________________________________________________| Description The preprocessor will evaluate the "expression", which must evaluate to a constant, and consider the result FALSE if it is a zero value or TRUE if it is a non-zero value. If the expression is TRUE, the C source code up to the corresponding "#endif" or "#else" will be processed; otherwise it will be ignored. Conditionals may be nested 256 deep. A constant_expression in the preprocessor can involve only integer con- stants and character constants. The binary operators permitted are: "+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "==", "!=", "<", ">", "<=", ">=", and "?:". The only unary operators permitted are: "-" and "~". `Language Definition - C Preprocessor` 2 - 41 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Example #if MAXLEN > 80 /* ensure external definition does */ #define MAXLEN 80 /* not exceed our maximum limit */ #endif Conditional test of an Identifier [#ifdef, #ifndef] These directives will test whether a macro name has been defined or un- defined. The result will be TRUE or FALSE respectively. _____________________________________________________________ | | | `#ifdef macname` | | `#ifndef macname` | | | | macname - is the symbolic name to be tested for its | | state - defined or undefined. | |_____________________________________________________________| Description If the identifier noted as "macname" has been previously defined via a "#define macname" and not forgotten via an "#undef macname", the result of the "#ifdef" test will be TRUE and the result of the "#ifndef" test will be FALSE; otherwise, the result of the "#ifdef" test will be FALSE and the re- sult of the "#ifndef" test will be TRUE. If the test result is TRUE, the C source code up to the corresponding "#endif" or "#else" will be processed; otherwise it will be ignored. Example #ifdef DOS6 #define MAXLEN 80 #else #define MAXLEN 64 #endif #ifdef DBUG static void dsply(); #endif Alternate Conditional Block [#else] The "#else" directive is used to establish an alternate block of C source code which is to be processed depending on the result of a previous conditional analysis. _____________________________________________________________ | | | `#else` | |_____________________________________________________________| `Language Definition - C Preprocessor` 2 - 42 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Description The block of source between the "#else" and the "#endif" will be pro- cessed and passed to the output stream only when the test state of the pre- ceding "#if", "#ifdef", or "#ifndef" was FALSE. This provides a construct similar to the "if (expression) statement_1; else statement_2;" in the C source language; however, in the case of the pre-processor, you can utilize this construct to conditionally insert alternative groups of C-source code into your program based on a single test. Multiple #else's are not accepted for a given #if; thus, threr can be only one "#else" per "#if". Example #ifdef DOS6 #define MAXLEN 80 #else #define MAXLEN 64 #endif Conditional Block Termination [#endif] The "#endif" directive is used to define the terminating boundary of a "#if", "#ifdef", or "#ifndef" conditional block. _____________________________________________________________ | | | `#endif` | |_____________________________________________________________| Description The "#endif" must be used to "close" any of the "#if" directives so the preprocessor knows the extent of the conditional block. Including Additional Files [#include] This directive permits additional files to be included into the C source stream. _____________________________________________________________ | | | `#include ` | | `#include "filespec"` | | `#include filespec` | | | | filespec - is the name of the C source or header file | | to be inserted into the source stream. | |_____________________________________________________________| Description This directive tells the C preprocessor to insert the file designated by "filespec" into the source stream being compiled. The "filespec" will default `Language Definition - C Preprocessor` 2 - 43 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` to an extension of "/H" if no extension is given. Includes may be nested 8 files deep. The "#include" is used quite frequently to merge the STDIO stan- dard header file and other header files into your compilation. Note that the preprocessor will accept all three forms of the "#include"; all forms are treated alike. Since the preprocessor makes use of the MC standard I/O package, it will accept filespecs of the form: "filename.ext" or "filename/ext". Example /* sample program to illustrate #include */ #include "stdio.h" main() { int x; x = -3 + 4 * 5 - 6; printf("%d\n",x) } Forcing Assembler Options [#option] This directive is passed through to the compiler which turns it into an assembler instruction. _____________________________________________________________ | | | `#option optname value` | | | | optname - is the symbol name to be assigned. | | | | value - is the optional value to be assigned to | | "optname" by an assembler DEFL instruction. | |_____________________________________________________________| Description The "#option" directive is used to pass symbol definitions from the C source code to the assembly phase. The "optname" must be a valid C identi- fier. The optional "value" must be an integer or character constant expres- sion. Escape sequences may be used in the constant. The compiler translates the "#option" directive to the form: @_OPTNAME DEFL value If the "value" is omitted, the DEFL statement will default to a value of negative one (-1). This indicates TRUE to the assembler. The #option directive is used in MC to generate a "request library search" assembler directive. This results in an automatic search of a speci- fied library during the linking phase. If your application will be using functions in either the installation library, IN/REL, or the high-level math library, MATH/REL, you will need to add the statement(s): #option INLIB` and/or `#option MATHLIB `Language Definition - C Preprocessor` 2 - 44 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` for the installation and high-level math libraries respectively. MC has reserved additional option names for use with the #option direc- tive. These are: ARGS - specifies the generation of argc and argv for use by main(); FIXBUFS - specifies buffer pre-allocation for standard I/O; MAXFILES - specifies the maximum number of simultaneously open files; REDIRECT - specifies the acceptance of standard I/O redirection; WILDCARD - specifies wildcard filespec expansion; The use of these options and "#option" in general is documented in chapter 3, "Running the Compiler" Including Assembler Source [#asm, #endasm] These pair of directives permit assembler source code to be placed directly in-line. _____________________________________________________________ | | | `#asm` | | `transparent assembly language code` | | `#endasm` | |_____________________________________________________________| Description The directive pair, "#asm" - "#endasm", can be used to insert assembly language source code directly within the C source file. It should be used ONLY when it is ABSOLUTELY necessary to write a routine in assembly language. Remember, any C source code file that has imbedded assembly language code is generally NOT portable. The more assembly language code you imbed, the less portable your programs become and the more you have to recode when trans- porting your program to another machine. All input past the "#asm" directive is passed unchanged into the output file except for preprocessor commands. Of course, since the output file is an assembly language source file, the statements following the "#asm" should be valid assembly source statements. The block of assembly statements is ended with the "#endasm" directive. Please note that the "#endasm" directive must be in column 1; otherwise the "#endasm" will not be recognized and any C source code following the "#endasm" will be passed uncompiled to the output file. Preprocessor commands within an "#asm"-"#endasm" construct are valid. This leads to some beneficial side effects. For example, a pure ASM source file may be #include'd, or "#if/#else/#endif" may be used to conditionally `Language Definition - C Preprocessor` 2 - 45 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` pass assembler source to the compiler. Be aware that all other text between a "#asm" - "#endasm" pair is passed unchanged to the output; no macro text re- placements are done. "#asm" - "#endasm" may not be nested. This escape to assembly language is provided as a convenient kludge mechanism only. It is not intended to be the normal way of interfacing assembly language functions to a C program. The proper way to interface to assembly language is to place the assembly function in a separate module, perhaps even in a user library if it is to be used frequently. This makes the program easier to transport to other systems, as the machine-dependent code is separated from the program source. See the Advanced Topics chapter for more information on assembly language programming in the MC environment. Line Number Control [#line] The preprocessor provides the "#line" directive to be able to pass source line number and filespec identification to the compiler. _____________________________________________________________ | | | `#line linenumber {filespec}` | | | | linenumber - is the number to be passed to the output. | | | | filespec - can be used to specify an optional filename. | |_____________________________________________________________| Description For purposes of diagnostic error messages, it is useful to be able to report on the physical line number of the specific source file where an error was detected. Since the use of "#include" provides a continuous stream of processed source to the compiler, it inserts appropriate "#line" statements which reveal when a source file switchover has occurred. The compiler expects "linenumber" to be the physical line number of the next source line. Where "filespec" is passed, that line is assumed to be originating from the iden- tified file. If "filespec" is omitted, the filespec is assumed to be the last file identified. `Language Definition - C Preprocessor` 2 - 46 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Program Example - SORTSYM The following C-source program makes use of many different C statements and variable types - including structures and unions. The purpose of the program is to obtain a page listing of the symbol table produced by MLINK, the linker provided with the MRAS assembler development system. A report sorted alphabetically by symbol name and numerically by symbol address is produced. A preponderance of comments have been added to explain the rationale behind the program. /* * SORTSYM - sort MLINK-generated symbol table by symbol and by address * Version 0.1 - Last update - 09/21/85 * Written by Richard N. Deglin * * Invoke via the syntax: sortsym outfile */ #include /* for standard definitions */ #include /* to define the stat structure */ #define RECORD union record #define RECLEN sizeof(RECORD) #define NAMELEN 15 #define ADDRLEN 4 struct stat fdat; /* file's stat data structure */ unsigned short nrecs, /* number of symbol entries */ fsize, /* SYM file size bytes to read */ i; /* loop variable */ char tempname[NAMELEN], /* workspace for swapping members */ tempaddr[ADDRLEN]; /* * The symbol table records generated by MLINK consist of * a name field (15 characters), followed by a space, * followed by a 4-byte hexadecimal address, terminated * by a new-line. Since we want to produce a listing * ordered by symbol name and by address, we declare a * union of two structures. The first structure (byname) * establishes the fields in the order read from the file. * The second structure shows the re-arrangement of fields * that we will create by moving the data. The union only * requires storage space for the largest member; thus, only * space for one record is actually required for the union. */ union record { struct { char name[NAMELEN]; /* symbol's name */ char space; /* interstitial space */ char addr[ADDRLEN]; /* symbol's address value */ `Language Definition - Program Examples` 2 - 47 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` char newline; /* terminating new-line */ } byname; /* first member of union record */ struct { char addr[ADDRLEN]; /* symbol's address value */ char space; /* interstitial space */ char name[NAMELEN]; /* symbol's name */ char newline; /* terminating new-line */ } byaddr; /* second member of union record */ } *record, /* A pointer to type "union record". We really */ /* need an array of records and would be able to */ /* use something like var[COUNT]; however, since */ /* we don't know how many records we need to */ /* obtain storage for, we use a pointer and */ /* allocate storage later with alloc() */ *base, /* A pointer to the base of the symbol records */ **prec, /* A pointer to the "array" of record pointers. */ /* This is similar to the specification, *var[]; */ /* however, since we don't know how big to make */ /* the array, we use a pointer to a pointer and */ /* dynamically allocate the array space. */ **recp; /* an extra one for work use */ /* * declare the following functions as type void so that the * compiler will flag an error if we try to use their * non-existant return value. */ void abend(), puterr(), tabify(); /* * the compare() function is needed by qsort(); even though * MC will assume a function to return an int if not explicitly * stated as such, declaring all such functions is a good habit * to get into */ int compare(); /* * declare as externs, all of the library functions used by * sortsym so that the compiler knows what kind of value, * if any, they return. */ extern int fstat(), qsort(), strncmp(), fputs(); extern char *alloc(), *move(); extern unsigned short read(), write(); /* * this is the main function */ `Language Definition - Program Examples` 2 - 48 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` main() /* * Since standard output will be used to write the processed * output, it will be necessary to write informative messages * to standard error. That's the purpose of puterr(). */ { puterr("\nReading..."); /* * fstat() will get the statistics of standard input since * it is referencing the file descriptor, STDIN. Note that * the second argument to fstat() needs to be a pointer to * a structure of type struct stat. Since fdat has been * defined to be of type struct stat, we use the "address of" * operator to denote a pointer_to. */ if (fstat(STDIN,&fdat) == EOF) /* stat the input file (stdin) */ exit(1); /* a return of EOF means an error */ /* * we use the st_size member which is the file size in bytes * to calculate the number of records to read. In that way, * we can read the entire file in one gulp. We also store the * file's size in "fsize". Note that st_size is cast to an * unsigned short (16-bit integer) since st_size is declared to * be a long in the stat header file. By the way, we subtract 1 * from the SYM file's size because MLINK adds a new-line as the * last byte of the file; that's ignored by sortsym. */ nrecs = (fsize = (unsigned short) fdat.st_size - 1) / RECLEN; /* * Now we get a little complicated. We want to make sure that: * (1) since we cast the size to a short, that it really can * fit into a short; the first test takes care of that; (2) that * we can allocate enough space for the input read buffer; the * second test takes care of that; and (3) that we can allocate * enough space for the pointers to each record; that's the * third test. Note also that since alloc() returns a pointer to * type char, it is cast to a "pointer to type RECORD" for the * read buffer allocation, and a pointer to a pointer of type * RECORD for the "array of pointers to the records". */ if (fdat.st_size > 0xffffL || ! (base = (RECORD *) alloc(fsize)) || ! (prec = (RECORD **) alloc(nrecs * sizeof(RECORD *)))) abend("SYM file too large\n"); /* * The file is now read. The read() function returns the number * of characters actually read. If this is not fsize, then an `Language Definition - Program Examples` 2 - 49 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` * error occurred. */ if (read(STDIN, (char *) base, fsize) != fsize) /* read SYM file */ exit(1); /* * We now generate the array of pointers to each record */ for ( i=0, record=base, recp=prec; i" object_of operator to connect the union's name to * its members. Also, since its members are structures, we * need the dot operator to connect the structure name * with its member [record->byname.name] */ puterr("\nReformatting..."); for (i = 0, record = base; i < nrecs; ++i, ++record) { (void) move(record->byname.name, tempname, NAMELEN); (void) move(record->byname.addr, tempaddr, ADDRLEN); (void) move(tempname, record->byaddr.name, NAMELEN); (void) move(tempaddr, record->byaddr.addr, ADDRLEN); record->byaddr.space = ' '; } /* * Some more status to inform you of where we are. We then * sort the array of records again with qsort() so that it * is ordered by address rather than alphabetically by name */ puterr("\nSorting by address..."); if (qsort((char *) prec, nrecs, sizeof(RECORD *), compare) == EOF) abend("Can't sort\n"); /* * A new order requires a new construction of the tabs to * construct a 3-across report format */ tabify(); /* * We now continue writing to the output file using stream output. * fputs() returns NULL if the output was successful, else EOF */ puterr("\nWriting by address..."); if (fputs("\nAddress sort:\n\n", stdout)) exit(1); /* * Each record is again written using block file writes. * As before, we compare the function's return value * which is the number of bytes actually written to how many * bytes we told it to write to detect error conditions */ for (i = 0, recp = prec; i < nrecs; ++i) if (write(STDOUT, (char *) *recp++, RECLEN) != RECLEN) `Language Definition - Program Examples` 2 - 51 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` exit(1); /* * This is the informative message we were looking for! We * are also leaving it up to exit() to close the output file * since we did not open it - it was standard output! */ puterr("\nDone\n"); } /* * This function is used to abort the program execution due * to some error. It uses puterr() to write the error message. */ void abend(s) char *s; { puterr(s); exit(1); } /* * The library qsort() function requires us to provide a comparison * function which compares two arguments. It needs to return <0, 0, * or >0 based on the comparison. We use strncmp() to compare at * most "RECLEN" characters. We could also have used memcmp(). */ int compare(a, b) char **a, **b; { return strncmp(*a, *b, RECLEN); } /* * This function is used to conveniently write a message to * standard error output since standard output is being used * to write the processed output */ void puterr(s) char *s; { (void) fputs(s, stderr); } /* * This function changes every two out of three "newlines" to * a tab in order to produce a three-across listing */ void tabify() { for (i = 0, recp = prec; i < nrecs; ++i, ++recp) (*recp)->byname.newline = (i + 1) % 3 ? '\t' : '\n'; (*--recp)->byname.newline = '\n'; /* last one always has newline */ } `Language Definition - Program Examples` 2 - 52 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Program Example - DCAL The next program can be used in a TRS-80 Model 4 enironment to calculate the rotational speed of a floppy disk drive. It is based on the knowledge of the actual processor clock speed to calculate the time it takes the floppy disk drive to rotate from index pulse to index pulse. The program demon- strates one form of the use of inline assembler code via the "#asm" - "#endasm" preprocessor directives. /* * DCAL - Used to calibrate the speed of a floppy disk drive * Version 0.1 - Last update - 11/20/85 * Written by Roy Soltoff - derived from DCAL/BAS by Tim Mann * * Invoke via the syntax: dcal drive# or dcal */ #include stdio.h /* to obtain standard constants */ #include math.h /* to request a search of MATH/REL */ #option INLIB /* to request a search of IN/REL */ #define CLOCK 2.02752e6 /* documented clock speed of a Model 4 in slow speed */ #define SELECT 0xf4 /* FDC port for drive select */ #define COMMAND 0xf0 /* FDC port for commands */ #define STATUS COMMAND /* FDC port for status - Note the macro is defined with a macro */ #define RESTORE 3 /* Controller command to restore a disk drive to track 0 */ #define BUSY 1 /* FDC status bit for busy */ #define VAR_TSTATE 46.0 /* This is the number of t-states taken up by the assembler code in the tight timing loop */ #define FIX_TSTATE 23.0 /* This is the number of t-states taken up by the assembler code executed outside of the tight timing loop but in the timing */ int ds[4] = {1,2,4,8}; /* drive select conversion table */ unsigned drive, ckpulse(); /* these will be unsigned ints */ double sbar = 0.0, /* smoothed speed, init to 0 */ rpm, /* speed at each iteration */ lo_rpm = 400.0, /* the lowest speed detected */ hi_rpm = 200.0; /* the hughest speed detected */ char buffer[81]; /* a general purpose input buffer */ /* * this is the main function - it makes use of command line * arguments; thus, it specifies the two arguments of main(), * argc [the count of arguments in argv] and argv [the array `Language Definition - Program Examples` 2 - 53 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` * of argument pointers]. */ main(argc, argv) int argc; /* declare argc an int */ char *argv[]; /* argv is a pointer to an array of character strings */ { /* * We first test to see if dcal was invoked with the drive * specification on the command line. If so, then argc would * be equal to 2; if not, then argc would be equal to 1 */ if (argc==2) drive = atoi(*++argv); else /* * otherwise, we request the user to enter the physical floppy * number [this is not necessarily the logical drive number if * the system also contains a hard drive(s). We make use of the * labeled statement to provide a "branch" point for the "goto". * You see, there is at least one place we can make use of "goto". * Use fputs() for output since we do not want a newline. * Use gets() for input as it strips the newline. */ { input: fputs("Enter floppy physical drive number <0-3> : ",stdout); if (!gets(buffer)) exit(0); /* we do not want to show an error */ drive = atoi(buffer); /* convert string entry to an int */ } /* * Test the input for validity. If not in the range 0-3, then * issue the request again (the "goto" will branch to "input" */ if (drive > 3) goto input; /* * The timing test needs a floppy diskette in the drive */ printf("Insert a disk in floppy %d and depress return",drive); /* * Index the drive select code based on the drive slot number * then use getchar() to accept the go ahead entry */ `Language Definition - Program Examples` 2 - 54 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` drive = ds[drive]; getchar(); /* * Tell how to "escape" from the continuous timing test. * This time we use puts() to add the newline character. */ puts("\nDepress any key to exit timing loop"); /* * Model 4's vary in effective CPU speed at the high speed because * some have more wait states than others; thus, use the system() * function to issue a DOS "system (slow)" command to force the * use of the 2 MHz clock speed. We do not have to bother to use * the portable execl() or execv() functions as this program is * very machine dependent and certainly not portable! */ system("system (slow)"); /* clock accurate at 2Megs only */ /* * Use outport() to issue the drive select command to the FDC * then restore the drive to track 0; the FDC needs a type II * command to be able to check index pulse status */ outport(SELECT,drive); outport(COMMAND,RESTORE); /* * Continue to select the drive until the BUSY flag is reset. * That's when we know the drive has been positioned to track 0 */ while (inport(STATUS) & BUSY) { outport(SELECT,drive); if (inkey()) /* we can poll the keyboard as a */ exit(0); /* means of escaping if desired */ } `Language Definition - Program Examples` 2 - 55 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` /* * This while loop continues to check the index pulse timing * until such time as a keyboard character is detected */ while (!inkey()) /* i.e. while no key is sensed */ { /* * The rotational speed is calculated from the equation: * * 60 seconds per minute times CPU speed in seconds * ------------------------------------------------------------- * (loop t-states times pulses per loop) plus fixed t-states */ rpm = 60.0*CLOCK/((double)ckpulse(drive)*VAR_TSTATE+FIX_TSTATE); /* * If speed this check is lower than the lowest already recorded, * then update the lowest stored; else if speed is greater than * the highest already recorded, then update the highest stored. */ if (rpm < lo_rpm) lo_rpm = rpm; if (rpm > hi_rpm) hi_rpm = rpm; /* * Calculate a "smoothed" speed by using 90 percent of our * previously calculated smoothed speed plus ten percent of * the speed detected on this check. Note that if the smoothed * speed has not already been established, sbar would be equal * to zero - its initialized value - and the smoothed speed is * just set equal to the speed this check. */ if (!sbar) sbar = rpm; sbar = sbar * 0.9 + rpm * 0.1; /* * Print out the driver's speed and the other statistics gathered. * The escape constant, "\x1d", is used to position the cursor * to the beginning of the line; thus, the printed data constantly * overprints itself rather than constantly scroll up the screen. * Note the use of the backslash, "\", to tell the MC preprocessor * to continue the C source line. */ printf("\x1dSpeed = %3.1f-%3.1f-%3.1f -- Smoothed speed = %4.1f",\ lo_rpm,rpm,hi_rpm,sbar); } /* this is the end of the while loop */ /* * Since we slowed up the normally "fast" CPU at the beginning `Language Definition - Program Examples` 2 - 56 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` * of the program, we now direct it to the "fast" mode. */ system("system (fast)"); /* * No explicit exit() is needed as the closing brace of main() * always "falls through" to exit(). */ } /* * This function contains the assembler routine which performs * the actual timing test of the disk drive. It is inserted * into the source stream via the "#asm" - "endasm" preprocessor * directive. Note that although the identifier "STATUS" is reused * here, the preprocessor does not replace it with the substitution * string "0xf0" as it is within a "#asm" - "#endasm" block. * We use a C function declaration to establish the function * environment; we could just as well have omitted it and * declared a "PUBLIC CKPULSE" and a "CKPULSE:" entry label. */ unsigned ckpulse(drive) int drive; { #asm STATUS EQU 0F0H ;FDC status port SELECT EQU 0F4H ;Floppy drive select port $GA DE ;Get drive number into register_DE DI ;Can't interrupt timing loop LD BC,2.SHL.8+SELECT L1 LD HL,0 ;Init or re-init counter to zero L2 OUT (C),E ;Select the drive INC HL ;Bump counter IN A,(STATUS) ;Get the status AND 2 ;Mask the index bit JP Z,L2 ;Loop until it's reset L3 OUT (C),E ;Select the drive INC HL ;Bump counter IN A,(STATUS) ;Get the status AND 2 ;Mask the index bit JP NZ,L3 ;Loop until it's set DJNZ L1 ;Do twice to check index to index EI ;Restore interrupts #endasm /* * The closing brace will provide the needed RET statement. * Since thus is an "unsigned" function, the returned value will * be in the HL register pair. */ } `Language Definition - Program Examples` 2 - 57 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` This page intentionally left blank `Language Definition` 2 - 58 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Keyboard Refresher Before you begin, remember that the DOS keyboard driver has a few extra keyboard combinations to generate some of the characters needed for C. It's probably a good idea to refresh your memory as to the key combinations. character key combination -------- --------------- [ CLEAR-COMMA \ CLEAR-SLASH ] CLEAR-PERIOD ^ CLEAR-SEMICOLON _ CLEAR-ENTER { CLEAR-SHIFT-COMMA | CLEAR-SHIFT-SLASH } CLEAR-SHIFT-PERIOD ~ CLEAR-SHIFT-SEMICOLON Operation The MCP preprocessor takes C source code as input and generates a pre- processed output file for the MC compiler's input. MC takes that preprocessed file as its input and generates an assembler source file as output. The as- sembler file is customized for either MISOSYS' MRAS or Microsoft's M80 assembler by means of a compiler option. The assembler of choice will produce a relocatable object module; this module must be combined with various mod- ules contained in the supplied libraries in order to produce an executable program file. This combining process is called "linking"; it is performed by the linker (MLINK or L80) supplied with your assembler of choice. Thus the output of the compilation process must be assembled and linked with any re- quired run-time library module before it can be executed. The first stage of the C language process is, of course, to create a C source file. The editor that is a part of your assembler package may be used for this purpose or you may use any other text editor. Your assembler manual should be consulted for all operations concerning the editor or assembler functions. _____________________________________________________________ | | | `Note for M80/L80 Usage` | | | | If you are using Microsoft's M80/L80 assembler/linker, | | you will have to add the preprocessor statement: | | | | `#include m80` | | | | in any C-source program file which includes your "main()" | | function. The "#include m80" must be inserted after all | | "#option" statements and before any global declarations. | | | | The identifier, "m80bgn", is reserved. | |_____________________________________________________________| `Running the Compiler` 3 - 1 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` The second stage of the C language process is the compilation of the C source using the MCP preprocessor and MC compiler. This produces an assembly source file. The third stage of the C language process is to convert that assembly language file into a relocatable object module. Your assembler does this. The fourth stage of the C language process is to link the relocatable module with any other relocatable modules you have developed for that program and any modules needed from the supplied libraries. Your linker will perform this step. Finally, your last stage is to test and debug your work. This generally requires a cycling through the above stages until you are satisfied that your program behaves as you intended. The JCL procedure shown below can automate the stages from compilation through linking. However, if you want to take direct control of each stage of the operation, you can invoke MCP and MC directly (as well as your assembler and linker). `Running the Compiler` 3 - 2 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Using Job Control Language A Job Control Language (JCL) file, "MC/JCL", presents the preprocessing, compilation, assembly, and linking as a job stream to the operating system. The JCL procedure requires minimal entry of commands by the programmer to create an executable CMD file. It provides eight options which are passed to the procedure in the JCL invocation. The JCL is invoked via the command: _____________________________________________________________ | | | `DO MC (N=progname{,parm}{,parm}{,...})` | | | | `progname` - Specifies the name of the C source file to | | be compiled and assembled into a CMD file. | | | | `a` - Specifies that the /ASM or /MAC file is to | | be assembled following a successful | | compilation. | | | | `c` - Specifies that the input C source file is | | to be preprocessed and compiled (default). | | | | `cc` - Specifies that the /ASM or /MAC file will | | have the C source imbedded as comments. | | | | `d` - Specifies the drive spec of the disk drive | | for all file I/O (defaults to d=1). | | | | `k` - Specifies that the intermediate files | | (/INT, /ASM or /MAC, and /REL) should be | | deleted after the /CMD file is generated. | | | | `l` - Specifies that the /REL module is to be | | linked with the needed libraries (default). | | | | `list` - Specifies that the assembly phase should | | produce a listing. | | | | `o` - Specifies that the /ASM or /MAC file is to | | be optimized prior to assembly. | |_____________________________________________________________| The beginning user need only be concerned with the "N=progname" para- meter as this is the means to identify the name of your C source program. The optional parameters are useful to the more knowledgable and experienced user. If you want to compile a program called "myprog" which resides on log- ical drive 1 and generate the finished CMD file with only one statement, then the command: DO MC (N=MYPROG) lets you sit back and relax while the machine does all of the work. If the /CCC file exists on another drive, use the "d" parameter. `Running the Compiler` 3 - 3 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Invoking the MCP Preprocessor The preprocessor is invoked via the command: _____________________________________________________________ | | | `MCP filespec {switch} {switch...}` | | | | `filespec` - A file specification for the input file. | | Only one filespec may be passed. | | | | `switch` - Represents an optional preprocessor switch. | | These switches are preceded with either a | | plus sign (+ = ON) or a minus sign | | ( - = OFF). The usable switches follow. | | | | `+dIDEN[=s]` - Specifies the definition of a macro with | | an optional replacement text string | | | | `+o[=spec]` - Specifies the generation of output and the | | output file specification. | | | | `-o` - Specifies that no output file should be | | written. | | | | `-p` - Designates that the display should not stop | | when error messages are emitted. | | | | `+t` - Specifies the output of an untokenized text | | file purely for debugging macros. | | | | `+uIDEN` - Undefines the designated identifier. | |_____________________________________________________________| The "filespec" may optionally include a file extension; however, if it is omitted, "/CCC" will be assumed. The drivespec is optional. It is recommended that you establish your C source files with the "CCC" file extension for uniformity and standardization. Switches: "Switch" options are specified by a plus "+" or minus "-" sign followed by the option letter and any additional information needed by the switch(es). +dIDENTIFIER[=TEXT] The plus "dee" switch will define a macro with optional replacement text from the command line. If text is not given, the macro is defined as "1". The minus "dee" syntax, "-d" is an alternative form. A parameterized macro defi- nition is acceptable. +o[=][FILE-OR-PARTSPEC] This plus "oh" switch instructs MCP to write its output to the named file. If a partspec is given, the output filespec is constructed from the `Running the Compiler` 3 - 4 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` name of the main input file plus the partspec. The output file's extension will be forced to "/TOK". -o The minus "oh" switch specifies that no output file is to be written. -p When this switch is ON (+p), the preprocessor will stop when any errors are found and displayed. Any key except BREAK will continue compilation. BREAK will abort the execution of the preprocessor at any time if this switch is on. If MCP was invoked from JCL, the JCL will also be aborted. This switch defaults to ON. If you wish to turn OFF the pause facility, enter "-p". +t The plus "tee" switch specifies that the output file generated by the preprocessor will be a pure text file. The normal type of file generated for input to the compiler phase is a tokenized file. Thus, the text output may be useful only for the purpose of checking your macro expansions for correct- ness. +uIDENTIFIER The plus "you" switch instructs MCP to ignore the first "#define" for this macro identifier encountered in the input stream. The minus "you" syn- tax, "-u" is an alternative form. `Running the Compiler` 3 - 5 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Invoking the MC Compiler MC is invoked to compile a preprocessed C source intermediate file. The command syntax is as follows: _____________________________________________________________ | | | `MC filespec {switch} {switch...}` | | | | `filespec` - A file specification for the input file. | | Only one filespec may be passed. | | | | `switch` - Represents an optional compiler switch(es) | | These switches are preceded with either a | | plus sign (+ = on) or a minus sign | | ( - = off). The usable switches follow. | | | | `+c` - Specifies that the C source code will be | | written to the output file as comments. | | | | `+f` - Specifies the FLOAT option for using the | | single precision floating point functions. | | | | `+m` - Designates that the output should be M80 | | compatible. | | | | `+o=spec` - Designates that output should be written to | the file identified. | | | | `-o` - Designates that no output file should be | | written. | | | | `-p` - Designates that the display should not stop | | when error messages are emitted. | |_____________________________________________________________| The compiler is invoked by entering a command line such as: MC CPROGRAM:2 which compiles the preprocessed C source file, "CPROGRAM/TOK:2", and gene- rates the output file, "CPROGRAM/ASM", on drive 2. The compiler will generate an MRAS compatible output file. The switches allow you to control certain features of the compiler. The simplest compilation command would simply be "MC PROGNAME" which compiles the file, "PROGNAME/TOK", and generates the output file, "PROGNAME/ASM". File Specifications There may be only one input file specification given on the command line. No extension should be given for a source file; the default extension "/TOK" is assumed. `Running the Compiler` 3 - 6 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` The output file specification defaults to the same name as the input file specified. MC will append the file extension "/ASM" (or "/MAC" when the +M switch is specified) to this name. The drive specifier, if any, of the input filespec is used as the drive specifier of the output file. The drive specifier should be given if the output file must be written to the same drive as the input file. The OUTPUT option may be used to specify a different file name or change the destination drive number. Assembler source code out- put may be suppressed by turning off the OUTPUT option. This can be helpful for quickly checking syntax without generating an output file. Compiler Switch Options Compiler option switches are turned on or off by a '+' or '-', respec- tively, followed by the name of the switch. The compiler regards any command line argument not beginning with a plus or minus as the input file specifi- cation. Only the first letter of the switch is examined, so partial spelling (or misspelling) is accepted. Certain switches have operands which are spec- ified by following the option name with '=' and the operand. For instance, "+o=myfile:3" will cause the output by the compiler to be written to "MYFILE/ASM:3" instead of the filespec that would have been the default. Comment This switch controls whether the preprocessed C source code will be written to the assembler output file as comments. The normal default is OFF. The C-source appearing as comments may be instrumental in your understanding the compiler output as it generates a minimally commented assembly source program. If you do need these "comments", then specify "+c". Float A compiler option has been included which allows you to change the de- fault floating point mode of the compiler. Use of the "+f" command line option will force the compiler to do float (32-bit) arithmetic in single precision mode, rather than in double mode. Also, this forces floating point constants to be interpreted in single precision. This results in faster operation with some loss of accuracy. Note that this is an MC extension to the K&R standard, and is not portable! The default mode of the compiler is "-f". Please consult Chapter 5, "Advanced Topics" before you attempt to use this option as there is a considerable difference in the way float arguments to functions are automatically casted depending on "+f" vs "-f". +M - Assembler Option Switch This switch will cause the compiler to generate code suitable for the Microsoft M80 relocatable assembler. The default file extension applied to the output file will be "/MAC". Note that throughout the remainder of this chapter, the output assembly file may be referred to as /ASM. Output=spec This switch controls the assembly file output of the compiler. If the switch is OFF (-o), no output file is generated. However, if it is ON, but no SPEC is given (+o), MC adds the file extension "/ASM" or "/MAC" to the name `Running the Compiler` 3 - 7 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` of the input file in order to create the output file specification. When a file specification is given for "spec", it becomes the name given to the output file. A default extension of "/ASM" (or "/MAC") is inserted if no ex- tension is given. If only a drive specification (":D") is given, the output file is written to that drive, with the same file name as the input file. This switch defaults to ON with no "spec" (+o). Pause When this switch is ON (+p), the compiler will stop when any errors are found and displayed. Any key except BREAK will continue compilation. BREAK will abort the execution of the compiler at any time if this switch is ON. If MC was invoked from JCL, the JCL will also be aborted. This switch defaults to ON. If you wish to turn OFF the pause facility, enter "-p". Creating an Executable CMD File Once the compiler has compiled your program into assembly language, you next need to use the MRAS or M80 macro assembler to create the relocatable (REL) object file. In order to provide control for certain MC library op- tions, the proper initialization in the CMD file, and ensure that all neces- sary runtime routines are linked with your program, a special assembler file, MC/ASM (MC/H for M80 use), has been provided. The MC/ASM file provided with your compiler package is generic to the environment of the operating system. The MC/ASM file is the file that is as- sembled in concert with your source file which contains main(). MC/ASM also includes special requests to direct the linker to search the libraries for needed modules during the link session. For a great deal of your programs, the only MC runtime routines needed will be located in the LIBC library. Since all C programs need some of the routines in LIBC/REL, that library is ALWAYS requested (as well as LIBA). The high-level math library, MATH/REL, will be searched if your program requested it via an "#option MATHLIB" or "#include math" compiler macro. Some useful routines are stored in the installation library, IN/REL. This library is not normally searched in order to save you linker search time when you need not refer to the IN/REL modules. However, it is very easy to force an automatic search of the installation library. All you need to do is specify an "#option INLIB" compiler macro in your C source program (similar to "#option MATHLIB"). For example, #option INLIB main() { int dot; for ( dot=0, dot < 128, dot++ ) set( dot, 0 ); } the`#option INLIB`statement will force a search of the installation library during the link session to resolve linkage to the set() function. If you are adding your own relocatable library, name it "USERLIB/REL". To force an automatic search of it, add this statement to your C program: `Running the Compiler` 3 - 8 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` #option USERLIB Compile-Time Directives Compile-time directives are used to convey information from your source file to the various stages of the program generation. These directives are initiated via the "#option" prefix. The syntax is as follows: #option {value} The "#option" directive is used to pass symbol definitions from the MC source code to the assembly phase of main() and the subsequent link phase. The must be a valid C identifier. Value must be a numeric or char- acter constant or constant expression. Escape sequences may be used in the constant. The compiler translates the "#option" directive to the form: @_OPTNAME DEFL value The "value" is optional (as shown above by apearing within braces). If the value is omitted, the DEFL statement will default to a value of negative one (-1). This indicates TRUE to the assembler. The "#option" directive is used in MC to invoke an automatic search of the installation library, IN/REL, or the high-level floating point math li- brary, MATH/REL. The automatic search is specified by the generation of "request library search" special link items in the resulting relocatable ob- ject module. This special link item is used by the linker. If your applica- tion will be using functions in either library, you will need to add the statement(s): #option MATHLIB #option INLIB for the high-level floating point math and installation libraries respec- tively. MC has reserved additional option names for use with the #option direc- tive. These are: args, fixbufs, maxfiles, redirect, and wildcard. The fol- lowing paragraphs describe their use. ARGS This is used to specify that your program {will}/{will NOT} be using command line arguments (argc, argv). MC will suppress the run-time code normally used to process arguments thus reducing the size of your CMD pro- gram. ARGS defaults to ON. FIXBUFS This is used to specify pre-allocation of buffers for standard I/O. If your program does not need dynamic memory allocation, then by specifying this option, you will inhibit the file I/O system provided in the standard library from automatically using dynamic allocation. This will result in a smaller `Running the Compiler` 3 - 9 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` executable program file. FIXBUFS defaults to OFF MAXFILES This is used to specify the maximum number of concurrently opened files permitted. The file I/O system provided in MC defaults to a maximum of 13; three additional are always provided which are needed for the standard files. Each requires memory overhead for storage. This storage space will normally be acquired dynamically (via alloc) and thus obtained only when files are opened; however, if FIXBUFS is ON, the storage space is always reserved at program execution regardless of whether files are opened or not. If your memory resources are strained and you are using FIXBUFS, then you may want to pay close attention to the maximum number of concurrently open files needed and set MAXFILES appropriately. MAXFILES defaults to 13. REDIRECT This is used to specify that your program {will}/{will NOT} be using standard I/O redirection (>, >>, <, #). MC will suppress the run-time code used to process I/O redirection thus reducing the size of your program. REDIRECT defaults to ON. WILDCARD This is used to specify that the resulting executable command program will be using command line wildcard filespec expansion; thus, the library routines needed to satisfy that request will be included during the link session. The use of this option is detailed in Chapter 5, Advanced Topics. WILDCARD defaults to OFF. `Running the Compiler` 3 - 10 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Assembly of the ASM file The assembly file output by the compiler is converted to a relocatable object module by means of your assembler. If the file was a standalone module (not to be linked with other separately compiled modules) containing the main() function and all other user-programmed funcitons needed for main(), then a sample syntax for the invocation of MRAS or M80 would be: MRAS MC +I=progname +o=progname -nl M80 progname=progname For MRAS use, this would assemble the file "MC/ASM" while it included "progname/ASM" into the source stream. For M80 use, it would assemble the source file "progname/MAC" while it included the file "MC/H" into the source stream (note that the MC/H header file was inserted into the C-source stream by your explicit "#include m80" preprocessor statement). Using either assem- bler, the assembly would generate the relocatable object file named "progname/REL". If you are developing an executable program which is composed of sepa- rately compiled modules, the procedure for accomplishing the mechanics of the compile, assemble, and link phases is covered in Chapter 5, Advanced Topics. Linking the relocatable object module The object module is linked with other modules supplied in the libraries by means of the linker supplied with your assembler. Sample syntax for link- ing the abovementioned module with your linker would be: MLINK progname +n=progname -e L80 progname-n,progname,-e:M80BGN L80 users please note the "M80BGN" operand on the "-e:name" linker switch. This is mandatory! It is used to specify the transfer address of the resul- ting executable command file. L80 users also note that the "progname-n" out- put file specification must be the first specification on the argument line. If you are developing an executable program which is composed of sepa- rately compiled modules, the procedure for accomplishing the mechanics of the compile, assemble, and link phases is covered in Chapter 5, Advanced Topics. `Running the Compiler` 3 - 11 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` This page intentionally left blank `Running the Compiler` 3 - 12 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` General Information The libraries provided with the MC compiler are a collection of useful and powerful functions that allow the user to interface with the world ex- ternal to the program, without having to know the specifics of the particular environment that the program is running in. Wherever possible, each function adheres to the standards of UNIX System V; the "SYSTEM V Interface Defini- tion" published by AT&T has served as the reference thereof. MC provides collections of common functions in four separate libraries: LIBA/REL, LIBC/REL, MATH/REL, and IN/REL; commonly called LIBA, LIBC, MATHLIB, and INLIB respectively. The functions are stored as relocatable ob- ject modules. Each file is thusly termed a relocatable object module library. The specific relocation format used is that documented by Microsoft, Digital Research, and MISOSYS in their respective assembler development systems. LIBA contains very low-level functions invoked by the compiler to per- form basic operations such as add, subtract, multiply, divide; logic opera- tions (or, and, exclusive or), stack access operations, and others. The functions included in LIBA are better termed routines. They are, in general, not available to the C-language programmer but are incorporated by the com- piler into the compiled output as needed by the program being compiled. LIBC contains most of the functions accessible to the C programmer. This library constitutes the "standard Library" functions as noted by most texts on the C language. You will find all of the functions associated with stream I/O and block device I/O. You will find the bulk of the character test oper- ations, the character manipulation operations, the memory access operations, the utility operations, as well as print formatting for all variable types except floats. The MATHLIB library includes all of the high-level floating point and double precision functions such as trigonometric operations, logarithmic operations, random number generation, and a complete print formatter for floats and doubles. In order to access any of the functions in this library, your source program must include the statement: #option MATHLIB In fact, if you are going to utilize any float or double, you need to specify this preprocessor directive. Most of the functions contained in MATHLIB must be declared prior to their use to inform the compiler of their "type. It's very easy to insert a bug into a program by neglecting to advise the compiler that a function returns a double such as with the declarative: extern double exp(); The high-level math functions provide error diagnostics per System V stand- ards. These standards dictate specific error number symbolic names as well as an exception structure for the data handling of error fixup. System V docu- ments a header file, "math.h", which includes all of the symbolic names associated with error handling, the definition of the exception structure, and a group of mathematical constants defined as symbolic names. The "math.h" header file included with MC also adds the declarations of all functions accessible to you in MATHLIB. By adding the preprocessor directive: `Function Libraries` 4 - 1 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` #include ` or `#include "math.h"` or `#include math` in all of your modules which need access to MATHLIB, you need not worry about function declarations. You will also have the symbolic names available to you. The "math" header file also adds the "#option MATHLIB" directive so you won't have to bother with it. The final library included with MC is INLIB. This library contains non- standard C functions that are implementation specific. If you desire to make your program portable to all System V compilers at the source level, then do not utilize any of these functions. However, if you intend to produce a locally used machine dependent program, then INLIB will provide you access to pixel graphic functions for plotting, string manipulations similar to BASIC, and special character device operations such as keyboard scanning and video cursor manipulation. The functions included in INLIB are automatically accessible to your program when you include the preprocessor directive: #option INLIB within your program's source. The pages which follow in this chapter provide detailed information on each function available to you. The chapter has been arranged purely in alphabetical order so that it may serve as a useful reference tool. Almost every function will appear on a separate page. The library where the function is stored is listed within parentheses appended to the function's name. To assist you in your search for a function which satisfies a particular need, the following classifications may be of assistance. Stream I/O functions: addext, checkc, clearerr, cleareof, fclose, fdopen, fdown, feof, ferror, fflush, fgetc, fgets, fileno, fopen, fprintf, fpup, fputc, fputs, fread, freopen, fscanf, fseek, ftell, fwrite, genspec, getc, getchar, gets, getw, inkey, ioctl, isatty, printf, putc, putchar, puts, putw, rewind, scanf, ungetc, ungetch, unlink Block I/O functions: addext, close, creat, dup, dup2, fcntl, fdown, fileno, fpup, fstat, genspec, gtty, ioctl, isatty, lseek, open, read, seek, stty, tell, ttyname, write Integer (int, long) math functions abs, atoi, btoi, itoa, itob, itoo, itou, itox, labs, lpower, ltoa, ltob, ltoo, ltou, ltox, otoi, otol, rand, srand, xtoi, xtol Single precision (float) math functions fabsf, fatn, fcos, fexp, ffix, fint, flog, fraise, frnd, fseed, fsin, fsgn, fsqr, ftan, ftoa `Function Libraries` 4 - 2 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Double precision (double) math functions acos, asin, atan, atan2, atod, ceil, cos, cosh, _ddv2, _ddv230, dfix, dint, dsgn, dtoa, exp, fabs, floor, fmod, frexp, hypot, ldexp, log, log10, matherr, modf, pow, sin, sinh, sqrt, tan, tanh Environment information functions asctime, ctime, curpos, cursor, freemem, inkey, inport, isalnum, isalpha, isascii, isbdigit, iscntrl, isdigit, islower, isodigit, isprint, ispunct, isspace, isupper, isxdigit, localtime, outport, perror, qsort, sysdate, systime, sys_errlist, time, tolower, toupper, _xlate Memory access functions: alloc, brk, calloc, fill, free, freemem, malloc, memccpy, memchr, memcmp, memcpy, memset, move, realloc, sbrk, swab, zero Plotting functions: box, circle, line, pixel, ploc, pmode, point, reset, set Program control operations abort, call, cmdi, execl, execovl, execv, exit, _exit, longjmp, matherr, option, setjmp, system, unlink String handling functions: atod, atof, atoi, atol, btoi, dtoa, ftoa, index, itoa, itob, itoo, itou, itox, ltoa, ltob, ltoo, ltou, ltox, otoi, otol, qsort, rindex, sprintf, sscanf, strcat, strchr, strcpy, strcspn, strepl, strept, strfind, stright, strleft, strlen, strmid, strncat, strncmp, strncpy, strpbrk, strrchr, strspn, xtoi, xtol `Function Libraries` 4 - 3 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` abort(LIBC) abort(LIBC) This function can be used to abort the executing program and optionally perform a "core dump". _____________________________________________________________ | | | `void abort()` | |_____________________________________________________________| Description Abort() will first attempt to close all open files, if possible. Abort() then issues the message: Program aborted via abort at X'xxxx' where "xxxx" is the program counter address when abort() was called. If the Operating System's Job Log device (*JL) is active, a formatted memory dump will be written to the job log device. The dump will include all addresses from the start of the executing program through the highest address used by the program. This will be in the format: zzzz: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx aaaaaaaa aaaaaaaa` where "zzzz" designates the origin of a 16-byte region, "xxxx..." indicates the contents of the region in hexadecimal, and "aaaa..." indicates the con- tents of the region in ASCII; characters outside the range 0x20 through 0x7f will be converted to a period (0x2b). Return Code There is no return from abort(). Example main() { /* notice that puts() adds a '\n' character */ puts("Catastropic failure in framus correctus"); /* notice that fputs() does not add a '\n' character */ fputs("\tDo you wish to abort ? ",stdout); if (tolower(getchar()) == 'y') abort(); else puts("You chose not to abort..."); } Try the example after issuing the DOS command: ROUTE *JL to *DO `Function Libraries` 4 - 4 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` abs(LIBC) abs(LIBC) This function is used to obtain the absolute value of an integer. _____________________________________________________________ | | | `int abs( ival );` | | `int ival;` | | | | ival - is the integer whose absolute value is to | | be determined. | |_____________________________________________________________| Description The abs() function returns the absolute value of its integer argument (i.e. abs(x) = x; abs(-x) = x;). Example #include stdio.h char inbuf[81]; main() { puts("Enter your number: EOF to exit"); while (TRUE) { if (!fgets(inbuf,80,stdin)) break; printf("Absolute value of your number is %d\n",abs(atoi(inbuf))); } } See also:`fabs(), fabsf(), labs() `Function Libraries` 4 - 5 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` acos(MATH) acos(MATH) This function is used to obtain the double precision Arc cosine. _____________________________________________________________ | | | `#include ` | | `double acos( xval );` | | `double xval;` | | | | xval - is the double whose Arc cos is desired. | |_____________________________________________________________| Description The Arc cos function obtains the double precision principal value of its argument. The range of the result is 0 to PI. The Arc cos is calculated from the relationship: Arc cos(x) = PI/2 + Arc sin(-x) Return Code If the magnitude of the argument to acos() is greater than one, zero is returned and errno is set to EDOM. In addition, a message indicating DOMAIN error is printed on the standard error output. This error-handling procedure may be changed with the function, matherr(). Example #include stdio #include math int i; char inbuf[81]; double d1,d2; main() { puts("Enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; d1 = acos(d2=atod(inbuf)); printf("d1 = %g; d2 = %g; errno = %d\n",d1,d2,errno); } } matherr(x) struct exception *x; { fprintf(stderr,"Type %d function error in %s...\n",x->type,x->name); fprintf(stderr," Args = %g,%g: ",x->arg1,x->arg2); return 0; } Enter your number: EOF to exit 0.9 |d1 = d2 0.9; = 0.451027; errno = 0 1.5 |Type 1 function error in acos... | Args = 1.5,0: argument domain error |d1 = d2 1.5; = 0; errno = 70 See also:`asin(), atan(), atan2(), errno `Function Libraries` 4 - 6 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` addext(IN) addext(IN) This function adds a default extension to a file specification. _____________________________________________________________ | | | `char *addext( filespec, defextn );` | | `char *filespec, *defextn;` | | | | filespec - the file specification to which the default | | extension should be added. | | | | defextn - the extension to add if filespec does not | | contain an extension. | |_____________________________________________________________| Description Addext is used to add a default file extension to a file specification if the file specification in question does not already contain an extension. It is useful for automatically adding standard extensions to files (i.e. CCC, CMD, TXT, ...) to minimize the input necessary in command lines. Return Code A pointer to the filespec is returned. Warnings The filespec argument must be a character array of at least dimension 15 to avoid writing beyond the end of the string. See also:`genspec() `Function Libraries` 4 - 7 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` alloc(LIBC) alloc(LIBC) This function is used to allocate a memory block. _____________________________________________________________ | | | `char *alloc ( nbytes );` | | `unsigned int nbytes;` | | | | nbytes - unsigned number of bytes needed. | |_____________________________________________________________| Description Alloc() is used to dynamically allocate memory during program execution. The complementary function, free(), is used to release memory allocated through alloc(). Alloc() may be used to get table or buffer space when the amount of memory space available is unknown, or when the program needs to dynamically allocate space for an array. Return Code If a memory block has been allocated, the value returned is a pointer to the memory block (pointer to char). If insufficient memory is available to satisfy the allocation, alloc() will return NULL (0). Warnings The program must not access memory outside of the area allocated. File access routines use alloc() and free() to establish and release File Control Areas (FCA's). The programmer cannot assume that memory not allocated is free for use, since later file opens may cause memory overlays. It is advised that the programmer always use the supplied dynamic allocation functions for mem- ory accessing. Example symtbsz -= symtbsz % symsiz; /* make integral */ if ((symtab = alloc(symtbsz)) == NULL) abend("not enough memory"); glbptr = startglb = symtab; See also:`brk(), calloc(), malloc(), realloc(), and sbrk() `Function Libraries` 4 - 8 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` asctime(LIBC) asctime(LIBC) This function is used to obtain the 26-character time string. _____________________________________________________________ | | | `#include ` | | `char *asctime( tm );` | | `struct tm *tm` | | | | tm - is a pointer to the structure which | | contains the broken down time. | |_____________________________________________________________| Description Asctime() takes the broken-down time data contained in the structure pointed to by the argument and converts it to an ASCII string of the form: Tue Oct 22 10:03:10 1985\n\0 Return Code A pointer to the resulting string is returned. Warning Note that the string itself is a local static and may be valid only immediately following the function call. Example #include "time.h" char *ctime(clock) long *clock; { struct tm *localtime(); char *asctime(); return asctime(localtime(clock)); } See also:`ctime(), localtime(), time() `Function Libraries` 4 - 9 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` asin(MATH) asin(MATH) This function is used to obtain the double precision Arc sine. _____________________________________________________________ | | | `#include ` | | `double asin( xval );` | | `double xval;` | | | | xval - is the double whose Arc sine is desired. | |_____________________________________________________________| Description The Arc sin function obtains the double precision principal value of its argument. The range of the result is -PI/2 to +PI/2. The Arc sin is calcu- lated from the relationship: Arc sin(x) = atan2(x,(sqrt(-x*x+1.0))) Return Code If the magnitude of the argument to asin() is greater than one, zero is returned and errno is set to EDOM. In addition, a message indicating DOMAIN error is printed on the standard error output. This error-handling procedure may be changed with the function, matherr(). Example #include stdio.h #include math.h int i; char inbuf[81]; double d1,d2; main() { puts("Enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; d1 = asin(d2=atod(inbuf)); printf("d1 = %g; d2 = %g; errno = %d\n",d1,d2,errno); } } matherr(x) struct exception *x; { fprintf(stderr,"Type %d function error in %s...\n",x->type,x->name); fprintf(stderr," Args = %g,%g: ",x->arg1,x->arg2); return 0; } Enter your number: EOF to exit -.9 |d1 = -1.11977; d2 = -0.9; errno = 0 -1.5 |Type 1 function error in asin... | Args = -1.5,0: argument domain error |d1 = 0; d2 = -1.5; errno = 70 See also:`acos(), atan(), atan2(), sin(), matherr() `Function Libraries` 4 - 10 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` atan(MATH); atan2(MATH) atan2(MATH); atan(MATH) These functions are used to obtain the double precision Arc tangent. _____________________________________________________________ | | | `#include ` | | `double atan( xval );` | | `double xval;` | | | | `#include ` | | `double atan2( yval, xval );` | | `double xval, yval;` | | | | xval, yval - is the double whose arc tangent is to be | | determined. | |_____________________________________________________________| Description The Arc tan function obtains the double precision principal value of its argument. The range of the result is -PI/2 to +PI/2. The Arc tan2 function uses the signs of both its arguments to determine the quadrant of the return value which will be in the range -PI to +PI. The atan() function is derived according to the algorithm given in SOFTWARE MANUAL FOR THE ELEMENTARY FUNC- TIONS by William J. Cody, Jr. and William Waite. Return Code If both arguments of atan2() are zero, zero is returned and errno is set to EDOM. In addition, a message indicating DOMAIN error is written to stand- ard error. This error-handling procedure may be changed with the function, matherr(). Example #include stdio #include math int i; char inbuf[81]; double d1,d2; main() { puts("Enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; d1 = atan(d2=atod(inbuf)); printf("d1 = %g; d2 = %g; errno = %d\n",d1,d2,errno); } } Enter your number: EOF to exit 1e15 |d1 = 1.5708; d2 = 1e+15; errno = 0 -2.5 |d1 = -1.19029; d2 = -2.5; errno = 0 0 |d1 = 0; d2 = 0; errno = 0 See also:`acos(), asin(), tan(), errno, matherr() `Function Libraries` 4 - 11 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` atod(MATH); atoi(LIBC); atof(MATH); atol(LIBC); ato?() These functions are used to convert character strings of digits to their numeric machine value. _____________________________________________________________ | | | `#include ` | | `double atod( string );` | | `float atof( string );` | | `char *string;` | | | | `int atoi( string );` | | `long atol( string );` | | `char *string;` | | | | string - is a string containing character digits | | valid for the number type. | |_____________________________________________________________| Description These functions are used to convert ASCII strings to their numeric value. Functions atoi() and atol() convert strings of decimal digits 0-9 to an int or long int. The converted integers will be modulo 65536 or modulo 4294967296 respectively. Conversion stops as soon as a character is detected which is not in the valid range. Functions atof() and atod() convert a string consisting of an optional sign followed by an optional sequence of decimal digits followed by an optional decimal point followed by an optional sequence of decimal digits followed by an optional exponent specifier ['e', 'E', 'd', or 'D'] followed by an optional exponent sign followed by an optional string of decimal digits to a float or a double respectively. The string cannot exceed 32 digits decimal digits! Example #include stdio #include math char inbuf[81], outbuf[81]; double dnum; main() { puts("Enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; dnum=atod(inbuf); fputs("Your number is: ",stdout); puts(dtoa(dnum,outbuf)); } } Enter your number: EOF to exit 1 |Your number is: 1.000000E+00 13.476 |Your number is: 1.347600E+01 -456.218e19 |Your number is: -4.562180E+21 See also:`sscanf(), dtoa(), ftoa(), itoa(), ltoa() `Function Libraries` 4 - 12 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` box(IN) box(IN) This function is used to plot a rectangle. _____________________________________________________________ | | | `int box( funcod, x1, y1, x2, y2 );` | | `int funcod; x1, y1, x2, y2;` | | | | funcod - an operation code to set (1) or reset (0) | | the pixels involved in the geometric plot. | | | | x1,y1 - the coordinate of the northwest corner of | | the rectangle. | | | | x2,y2 - the coordinate of the southeast corner of | | the rectangle | |_____________________________________________________________| Description The "box()" function will plot a rectangle around the diagonal specified by the coordinate point pairs, (x1,y1) and (x2,y2). If the coordinates spec- ify either equal values of x (x1 = x2) or equal values of y (y1 = y2), then the rectangle will diminish to a line. The rectangle will collapse to a point if both x1=x2 and y1=y2. Box() supports virtual points which means that your plot does NOT have to limit itself to the CRT image area. For example, a "box(1,10,20,190,25);" function describes a rectangle partially out of the CRT image. In this exam- ple, only a portion of a rectangle will be plotted. Return Code A minus one (-1) indicates that the coordinate points (x1,y1), (x2,y2), or a portion of any plot is out of range (i.e. virtual and does not appear in the CRT image). A minus three (-3) will be returned if the function code passed is invalid (not in the range <0-1>. Example #option INLIB #define X 79 /* 80 x 24 screen size */ #define Y 35 #define DRAW 1 int x1, y1, x2, y2; main() { for (x1=X,y1=Y,x2=X+1,y2=Y+1; x1 >= 0; x1--,y1--,x2++,y2++) box(DRAW, x1, y1, x2, y2 ); } See also:`circle(), line(), pixel(), ploc(), pmode(), point(), reset(), set() `Function Libraries` 4 - 13 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` brk(LIBC) brk(LIBC) This function is used to set the program break address. _____________________________________________________________ | | | `int brk( address );` | | `char *address;` | | | | address - is to be the lowest machine address not | | used by the program. | |_____________________________________________________________| Description The lowest memory address not used by the program (exclusive of the program stack) is termed the "break". This function will set the program break to "address". One greater than the highest address used by your program for program code and static variable storage is defined as "$PROGEND". One greater than the highest memory address allocated is defined as $LOMEM. $LOMEM is initially equal to $PROGEND. MC maintains a pointer to this loca- tion called $FREEP. The break argument, "address", may not be below $FREEP nor greater than (STACK_POINTER less 1024 bytes). Warning NEVER use brk() with any dynamic allocation routine such as alloc(), calloc(), free(), or malloc() or with the standard I/O package without spec- ifying "#option FIXBUFS". Return Code Zero is returned if the break could be set while a -1 is returned if the break exceeded the bounds of the available memory and thus could not be set. Example #include #option FIXBUFS char *brk(), sbrk(); main() { char *membuf, *lomem; lomem = sbrk(0); /* Get current value of $LOMEM */ printf("$LOMEM pointer = X'%04x'\n",lomem); membuf=sbrk(1024); /* grab a 1K buffer */ printf("$LOMEM pointer = X'%04x'\n",sbrk(0)); if (!brk(lomem)) printf("$LOMEM pointer = X'%04x'\n",lomem); else puts("Brk error"); } $LOMEM pointer = X'54cf' $LOMEM pointer = X'58cf' $LOMEM pointer = X'54cf' See also:`alloc(), calloc(), free(), malloc(), sbrk() `Function Libraries` 4 - 14 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` btoi(LIBC) btoi(LIBC) This function is used to convert a character string of binary digits to its integer value. _____________________________________________________________ | | | `int btoi( string );` | | `char *string;` | | | | string - is a string containing binary digits <0-1> | |_____________________________________________________________| Description This C function obtains the machine value of a string of binary digits in character form (i.e. composed of nothing but zeroes and ones). Left trun- cation of the integer value takes place if an excess number of digits is present (i.e. ival=btoi("10000000000000001"); would result in the integer value of 1 decimal). Conversion stops as soon as the first character not in the valid range is detected. Example #include stdio.h char inbuf[81]; int ival; main() { puts("Enter your binary number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; ival=btoi(inbuf); printf("Your number in decimal is: %d\n",ival); } } Enter your binary number: EOF to exit 10110101 |Your number in decimal is: 181 11111111 |Your number in decimal is: 255 100000001 |Your number in decimal is: 257 10000000000000001 |Your number in decimal is: 1 See also:`atoi(), atol(), otoi(), otol(), xtoi(), xtol() `Function Libraries` 4 - 15 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` call(IN) call(IN) This is a generalized machine specific assembly language and system SVC interface routine. _____________________________________________________________ | | | `#include ` | | `int call( address, reg );` | | `char *address; union REGS *reg;` | | | | address - is the machine address or SVC to call. | | | | reg - is a pointer to a structure containing the | | machine's register contents. | |_____________________________________________________________| Description A generalized assembly language interface routine, call(), is available in the installation library. "Reg" is either an integer array of dimension 6 which should contain the quantities you want placed into the register pairs AF, BC, DE, HL, IX, and IY for regs[0]-regs[5] respectively, prior to calling the routine at location "address", or "reg" is a pointer to a structure which contains the quantities to be placed into the machine's registers. The "reg" array or structure will be loaded with the register contents that existed upon return from the called routine. On SuperVisor Call accessible systems, an "address" value of less than 256 will be interpreted as an SVC reference in lieu of a CALL address. The call() function will then use the "address" value as the SVC number. A union which defines the word and byte structures for the Z-80 register set is provided in the z80regs header file. Use of the union is demonstrated extensively in the example below. Return Code The return code will be FALSE (0) if the machine's Z-flag is set upon return from the called routine; otherwise, the return code is TRUE (1). Example A rather long example which illustrates the use of the REGS union in various invocations of call() appears on the following page. Note that the example is designed for an SVC-driven operating system. `Function Libraries` 4 - 16 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` #include #define CKDRV 33 #define DATE 18 #define DODIR 34 #define DSPLY 10 #define TIME 19 #option INLIB int rc,d; char *ptr, buf[100]; union REGS reg; main() { puts("Test of call()..."); for ( d=0; d<8; ++d ) { reg.C=d; /* Set C to the drive number */ rc=call(CKDRV,®); printf("Drive %d %s%s\n",d,rc?"not ":"","ready"); if (reg.F&1) puts("Drive is write protected"); } wait(); dt(DATE,"Date"); dt(TIME,"Time"); reg.HL="This is a message\n"; call(DSPLY,®); wait(); reg.B=4; reg.C=0; /* DODIR; function=4, drive=0 */ reg.HL=buf; call(DODIR,®); strmid(buf+80,buf,0,8); strmid(buf+90,buf,8,8); printf("%s %s free: %dK\n\n",buf+80,buf+90,buf[18]+(buf[19]<<8)); reg.BC=0; /* DODIR; function=0, drive=0 */ call(DODIR,®); wait(); } wait() { puts("\nHit any key"); getchar(); clscrn(); } dt(addr,str) char *addr,*str; { reg.HL=buf; call(addr,®); *(ptr=reg.HL)=0; printf("%s: %s\n",str,buf); } clscrn() { fputs("\x1c\x1f",stdout); } `Function Libraries` 4 - 17 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` calloc(LIBC) calloc(LIBC) This function is used to allocate a zeroed memory block. _____________________________________________________________ | | | `char *calloc ( nelem, elsize);` | | `unsigned int nelem, elsize;` | | | | nelem - is the number of elements of "elsize" to | | be allocated. | | | | elsize - is the size of an element in bytes; use | | sizeof(elem) for portability. | |_____________________________________________________________| Description Calloc() is used to dynamically allocate memory during program execu- tion. The complementary function, free(), is used to release memory allocated through calloc(). Calloc may be used to get table or buffer space when the amount of memory space available is unknown, or when the program needs to dynamically allocate space for an array and the space must be filled with binary zeroes. Return Code If a memory block has been allocated, the value returned is a pointer to the memory block (pointer to char). If insufficient memory is available to satisfy the allocation, calloc() will return NULL (0). Warnings The program must not access memory outside of the area allocated. File access routines use alloc() and free() to establish and release File Control Areas (FCA's). The programmer cannot assume that memory not allocated is free for use, since later file opens may cause memory overlays. It is advised that the programmer always use the supplied dynamic allocation functions for mem- ory accessing. Example if ((symtab = calloc(MAXSYMS,sizeof(SYMBOL))) == NULL) abend("not enough memory"); glbptr = startglb = symtab; See also: alloc(), brk(), malloc(), realloc(), and sbrk() `Function Libraries` 4 - 18 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ceil(MATH) ceil(MATH) This function obtains the ceiling of a double. _____________________________________________________________ | | | `#include ` | | `double ceil( argx );` | | `double argx;` | | | | argx - is the double whose ceiling is desired. | |_____________________________________________________________| Description The ceiling of x is the smallest integer value not less than x; it is returned as a double. Example #include stdio.h #include math.h char inbuf[81]; double d1,d2; main() { puts("Ceil: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; d2 = ceil(d1=atod(inbuf)); printf("d1 = %g; d2 = %g; errno = %d\n",d1,d2,errno); } } Ceil: enter your number: EOF to exit -1.7 |d1 = -1.7; d2 = -1; errno = 0 1.7 |d1 = 1.7; d2 = 2; errno = 0 See also:`fabs(); floor(), fmod() `Function Libraries` 4 - 19 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` checkc(LIBC) checkc(LIBC) This function is used to detect whether or not a character is available from an input file stream. _____________________________________________________________ | | | `int checkc( stream );` | | `FILE *stream;` | | | | stream - the file pointer of the stream as returned | | from a successful fopen(). | |_____________________________________________________________| Description For certain types of applications, it is useful to know if a character is available for input prior to requesting the input via getc() [or other character input function]. For instance, a terminal program usually needs to toggle between scanning for standard input and input from a communications line. Since getc() will wait until a character is available, it can lock up such a program until a character is available from the stream. With checkc(), you can refrain from invoking getc() until a character is known to be avail- able. Return Code There are three possible return codes. TRUE is returned if a character is available, or an EOF is detected from the file stream. FALSE is returned if a character is not available. EOF is returned if the file pointer refer- ences a closed file or a prior EOF had been detected. Warnings The stream pointer passed as the argument of the function must be one obtained from fopen() or must be the standard input device [stdin]. Also, checkc() uses ungetc() to store any input character; therefore, you should refrain from invoking ungetc() immediately following a checkc() invocation. Example while (TRUE) { if (checkc(stdin)) getterm(); else if (checkc(comm)) getcomm(); } See also:`putc(), putchar(), getc(), getchar(), ungetc(), ungetch() `Function Libraries` 4 - 20 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` circle(IN) circle(IN) This function is used to plot a circle (or close to it). _____________________________________________________________ | | | `#option INLIB` | | `int circle( funcod, x1, y1, r1 );` | | `int funcod, x1, y1, r1;` | | | | funcod - an operation code to set (1) or reset (0) | | the pixels involved in the geometric plot. | | | | x1,y1 - the coordinate of the circle's center. | | | | r1 - the radius of the circle in "y" units. | |_____________________________________________________________| Description The "circle()" function will plot a circle at coordinate center point (x1,y1) of radius r1. The integer value, "r1", specifies the radius of the circle. Since block graphics are generally taller than their width, it is necessary to specify the radius in units of either "x" or "y". Within these plotting functions, "r1" is a value representing the radius in "y" units. Virtual Points The concept of virtual points is an important one. What it means is that your plotting routines do NOT have to limit themselves to the CRT image area. For example, a circle(1,0,0,20); function describes a circle about the origin. This means that a portion of the circle would be plotted off of the CRT image. The plotting functions permit your arguments to describe such "virtual" images; however, any portion of the geometric shape that would be outside of the CRT image area is inhibited. Thus, in the above example, only a portion of a circle (an arc) will be plotted. Return Code A return code of minus one (-1) indicates that the coordinate point (x1,y1) or a portion of the plot is out of range (i.e. virtual and does not appear in the CRT image). A minus three (-3) will be returned if the function code passed is invalid (not in the range <0-1>). Example circles(sw) /* concentric circles */ { int r; for (r=1;r<36;r+=3) circle(sw,79,35,r); } See also:`box(), line(), pixel() `Function Libraries` 4 - 21 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` cleareof(LIBC) cleareof(LIBC) This function is used to clear the end-of-file condition detected on an input stream. _____________________________________________________________ | | | `int cleareof( stream );` | | `FILE *stream;` | | | | stream - the file pointer of the stream as obtained | | from fopen(). | |_____________________________________________________________| Description When an end-of-file condition is detected on an input stream (say standard input, for instance), a flag bit is set in the File Control Area flag to indicate this condition. Subsequent requests to input a character from that file stream will always return a constant EOF. The cleareof() function can be used to reset that EOF condition flag. It is useful primarily to clear the EOF condition established by the key for standard input. Return Code If the file pointer references a closed file stream or the end-of-file bit is not set in the file control area, cleareof() will return EOF as de- fined in the stdio header file. A return code of NULL (0) indicates successful clearing of the flag. Warnings The file pointer passed as the argument of the function must be one ob- tained from fopen() or one of the standard devices [stdin, stdout, or stderr]. Example if (getchar() == EOF ) { cleareof(stdin); break; } See also:`clearerr(), errno(), ferror(), perror(), sys_errlist() `Function Libraries` 4 - 22 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` clearerr(LIBC) clearerr(LIBC) This function is used to clear any error condition detected on an input or output stream. _____________________________________________________________ | | | `int clearerr( stream );` | | `FILE *stream;` | | | | stream - the file pointer of the stream as obtained | | from fopen(). | |_____________________________________________________________| When an error condition is detected on a stream or block device, a flag bit is set in the file control area to indicate this error condition and the DOS error number is stored in the File Control Area for access by ferror(). The UNIX error number associated with the error will also be stored in the global error variable, errno. The EOF flag bit is also set. Subsequent requests to input a character from that file stream will always return a constant EOF. The clearerr() function can be used to reset the ERROR and EOF condition flags. Return Code If the file pointer references a closed file, cleareof() will return EOF as defined in the stdio header file. A return code of NULL (0) indicates successful clearing of the flag. Warnings The stream pointer passed as the argument of the function must be one obtained from fopen() or one of the standard devices [stdin, stdout, or stderr]. Example if (c!=putchar(c)) { errnum = ferror(stdout); clearerr(stdout); break; } See also:`cleareof(), errno, ferror(), perror(), sys_errlist() `Function Libraries` 4 - 23 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` close(LIBC) close(LIBC) This function is used to close a block device which has been obtained by a call to either open(), creat(), dup(), dup2(), or fcntl(). _____________________________________________________________ | | | `int close( fildes );` | | `int fildes;` | | | | fildes - the file descriptor of the block device. | |_____________________________________________________________| Description Close() is used to close an open file and to free the File Control Area (FCA) and I/O buffer for subsequent re-use. The file descriptor passed to close must have been obtained from either open(), dup(), dup2(), fcntl(), or creat(). In MC, exit() also closes files; however, the programmer should use close() on opened files to ensure compatibility and portability. Return Code A return code of NULL (0) indicates successful closing of the file. If any error is detected, EOF (-1) will be returned. Example creat_file(name) char *name; { int i,fd; if ((fd=creat(name,0777))==EOF) open_error(name); for (i=0;i<10000;i++) { if ((write(fd,itoa(i,record),10))!=10) { printf("Error in writing %s\n",name); exit(-1); } cursor(10,3); /* position cursor */ printf("Writing record %5d\n",i); } close(fd); } See also:`creat(), dup(), fcntl(), fdown(), fstat(), lseek(), open(), read(), seek(), tell(), write() `Function Libraries` 4 - 24 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` cmdi(LIBC) cmdi(LIBC) This function will exit the program and invoke a DOS command. _____________________________________________________________ | | | `void cmdi( cmdstr );` | | `char *cmdstr;` | | | | cmdstr - a pointer to the string which contains the | | DOS command which is to be executed. | |_____________________________________________________________| Description The cmdi() function will close all open files which have the "close on exec" flag set and then schedule the DOS execution of the command either pointed to by the argument or by the command contained in the string passed as the argument to the function. This could be used, for instance, to chain to another C program. Warnings For portability across C compilers, the UNIX functions execv() or execl() should be used in lieu of cmdi(). Example char buf[81]; /* string space for command string */ main() { puts("Test of cmdi()\n"); fputs("Enter command: ",stdout); gets(buf); /* Get DOS command from user */ cmdi(buf); /* Exit this program and execute the command */ puts("This string will not be written"); } See also:`system(), execl(), execv() `Function Libraries` 4 - 25 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` cos(MATH) cos(MATH) This function is used to obtain the double precision cosine. _____________________________________________________________ | | | `#include ` | | `double cos( argx );` | | `double argx;` | | | | argx - is the double expressed in radians whose | | cosine is to be determined. | |_____________________________________________________________| Description This function will obtain the double precision cosine of its argument; the argument must be expressed in radian measure. Example #include stdio #include math char inbuf[81]; double d1,d2; main() { puts("Cos: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; d2 = cos(d1=atod(inbuf)); printf("d1 = %g; d2 = %g; errno = %d\n",d1,d2,errno); } } Cos: enter your number: EOF to exit -1.75 |d1 = -1.75; d2 = -0.178246; errno = 0 1.75 |d1 = 1.75; d2 = -0.178246; errno = 0 .5 |d1 = 0.5; d2 = 0.877583; errno = 0 See also:`acos(), asin(), atan(), cosh(), sin(), sinh(), tan(), tanh(), fcos() `Function Libraries` 4 - 26 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` cosh(MATH) cosh(MATH) This function is used to obtain the hyperbolic cosine of a double. _____________________________________________________________ | | | `#include ` | | `double cosh( argx );` | | `double argx;` | | | | argx - is the double expressed in radians whose | | hyperbolic cosine is to be determined. | |_____________________________________________________________| Description This function will obtain the double precision hyperbolic cosine of its argument. The hyperbolic cosine of x is defined as [[exp(x)-exp(-x)]/2]. Example #include stdio #include math char inbuf[81]; double d1,d2; main() { puts("Cosh: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; d2 = cosh(d1=atod(inbuf)); printf("d1 = %g; d2 = %g; errno = %d\n",d1,d2,errno); } } Cosh: enter your number: EOF to exit 0 |d1 = 0; d2 = 1; errno = 0 .5 |d1 = 0.5; d2 = 1.12763; errno = 0 10 |d1 = 10; d2 = 11013.2; errno = 0 -10 |d1 = -10; d2 = 11013.2; errno = 0 See also:`acos(), cos(), exp(), sinh(), tanh() `Function Libraries` 4 - 27 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` creat(LIBC) creat(LIBC) This function is provided to create new files or to rewrite old files. _____________________________________________________________ | | | `int creat( path, pmode);` | | `int pmode; char *path;` | | | | path - a pointer to the string containing the | | file specification. | | | | pmode - the file's assigned protection mode. | |_____________________________________________________________| Description If the specified file must be created, it will be created with the pro- tection mode specified by the "pmode" argument. If the file is existing, creat() will truncate it to a length of zero. In either case, the access "OFLAG" will be established as O_WRONLY. To maintain portability with the UNIX file system, pmode is interpreted as a nine-bit integer specifying read, write, and execute permission for the owner of the file [bits 8-6], for the owner's group [bits 5-3], and for all others [bits 2-0]. Only the "all others" 3-bit field is used to establish the file protection under LDOS/TRSDOS. This is translated as follows: read write execute LDOS/TRSDOS read write execute LDOS/TRSDOS ---- ----- ------- ----------- ---- ----- ------- ----------- 0 0 0 NO ACCESS 1 0 0 READ 0 0 1 EXEC 1 0 1 READ 0 1 0 WRITE 1 1 0 WRITE 0 1 1 WRITE 1 1 1 FULL If the file specification included a password field, then this password will apply only to the OWNER's access (UPDATE password for LDOS 5.1). The USER's access field (ACCESS password for LDOS 5.1) will be changed to blanks. Return Code If the file is properly created, its file descriptor will be returned. If an error is detected in creating the file, creat() will return EOF (-1). Example creat_file(name) char *name; { int fd; if ((fd=creat(name,0777))==EOF) open_error(name); if ((write(fd,header,RECLEN))!=RECLEN) printf("Error in writing %s\n",name); close(fd); } See also:`close(), open() `Function Libraries` 4 - 28 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ctime(LIBC) ctime(LIBC) This function is used to obtain the ASCII 26-character time string. _____________________________________________________________ | | | `char *ctime( clock );` | | `long *clock;` | | | | clock - is a pointer_to_long which contains the | | time as retrieved by time(). | |_____________________________________________________________| Description This function converts the UNIX time stored as a long integer obtained from a function such as time() into a 26-character string of the form: Tue Oct 22 11:09:08 1985\n\0 All of the fields of the time string have a constant width. Example #option INLIB main() { long clock, time(); char *ctime(); clock = time( (long *) 0); printf("At the tone, the time will be [%ld]: ",clock); puts(ctime(&clock)); system("date"); system("time"); } At the tone, the time will be [500036062]: Tue Nov 05 10:54:22 1985 Tue, Nov 5, 1985 10:54:39 See also:`asctime(), localtime(), time() `Function Libraries` 4 - 29 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` curpos(IN) curpos(IN) This function is used to obtain the position of the CRT's cursor. _____________________________________________________________ | | | `#option INLIB` | | `unsigned curpos();` | |_____________________________________________________________| Description The current location of the cursor can be recovered with the curpos() function. It returns the cursor position as an encoded value. The cursor row is in the high-order byte while the cursor column occupies the low-order byte of the integer return code. Example #option INLIB main() { unsigned int crtrow, crtcol; puts("\x1c\x1f"); /* home, clear, CR */ crtrow=(crtcol=curpos())>>8; /* get curpos; calc row */ crtcol&=0x0ff; /* calc column */ printf("crt: row=%d, col=%d",crtrow,crtcol); } crt: row=1, col=0 DOS Ready See also:`cursor() `Function Libraries` 4 - 30 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` cursor(IN) cursor(IN) This function is used to move the cursor to a designated CRT position. _____________________________________________________________ | | | `#option INLIB` | | `int cursor( col, row );` | | `int col, row;` | | | | col - is the column of the new position. | | | | row - is the row of the new position. | |_____________________________________________________________| Description To reposition the cursor on the CRT screen, use the cursor() function. The cursor is re-positioned to the location identified by the arguments. Return Code If the position that would result is not on the CRT screen, a range error (-1) is returned. "col" must be in the range, <0-X>, while "row" must be in the range, <0-Y>. For 64 x 16 screen sizes, the X and Y limits are 63 and 15. For 80 x 24 screen sizes, the X and Y upper limits are 79 and 23 respectively. Example #option INLIB write_file(fildes) int fildes; { int i; for (i=0;i<10000;i++) { if ((write(fildes,itoa(i,record),10))!=10) return i; cursor(10,3); /* position cursor to row 3, col 10 */ printf("Writing record %5d\n",i); } return NULL; } See also:`curpos() `Function Libraries` 4 - 31 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` _ddv2(MATH); _ddv230(MATH) _ddv230(MATH); _ddv2(MATH) These functions obtain a fast divide_by_2 and a divide_by_2^30 of a double. _____________________________________________________________ | | | `#include math.h` | | `double _ddv2( argx );` | | `double argx;` | | | | `double _ddv230( argx );` | | `double argx;` | | | | argx - is the argument for which the divide | | operation is desired. | |_____________________________________________________________| Description These two functions are special and non-standard. Use them only if you are not interested in portability. They perform a fast divide operation on a double. _ddv2() divides a double by 2.0. _ddv230 divides a double by 2^30. Example #include double ldexp(argfr, exp) double argfr; register int exp; { static double huge, fr; static int neg; static int i; double frexp(), _ddv230(); fr = argfr; huge = HUGE_VAL; neg = 0; if (fr < 0.0) { fr=-fr; neg=1; } fr = frexp(fr, &i); while (fr < 0.5) { fr *= 2.0; --i; } exp += i; if (exp > 127) { errno=ERANGE; return neg ? -huge : huge; } if (exp < -127) { errno=ERANGE; return 0.0; } while (exp > 30) { fr *= (1L << 30L); exp -= 30; } while (exp < -30) { fr = _ddv230(fr); /* fr /= (1L << 30L) */ exp += 30; } if (exp > 0) fr *= (1L << exp); if (exp < 0) fr /= (1L << -exp); if (neg) fr = -fr; return fr; } `Function Libraries` 4 - 32 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` dfix(MATH) dfix(MATH) This function obtains the truncated value of a double. _____________________________________________________________ | | | `#include math.h` | | `double dfix( argx );` | | `double argx;` | | | | argx - is the double value to truncate. | |_____________________________________________________________| Description The truncated value is obtained by dropping all digits to the right of the decimal point so the result is a whole number. If argx is negative, dfix(argx) is equivalent to dint(x)+1.0. Example #include stdio.h #include math.h char inbuf[81]; double d1,d2; main() { puts("Dfix: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; d2 = dfix(d1=atod(inbuf)); printf("d1 = %g; d2 = %g\n",d1,d2); } Dfix: enter your number: EOF to exit -1.275 |d1 = -1.275; d2 = -1 1.275 |d1 = 1.275; d2 = 1 See also:`dint(), floor(), ceil() `Function Libraries` 4 - 33 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` dint(MATH) dint(MATH) This function obtains the integer part of a double. It is identical to the standard math function, floor(). _____________________________________________________________ | | | `#include math.h` | | `double dint( argx );` | | `double argx;` | | | | argx - is the double for which the integer part | | is desired. | |_____________________________________________________________| Description This function obtains the largest integer not greater than "argx". The "dint()" function has been provided only for the sake of a name compatibility with other languages. For the sake of portability among C compilers, it is recommended that you use the equivalent function, floor(). Example #include stdio.h #include math.h char inbuf[81]; double d1,d2; main() { puts("Dint: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; d2 = dint(d1=atod(inbuf)); printf("d1 = %g; d2 = %g\n",d1,d2); } } Dint: enter your number: EOF to exit -1.275 |d1 = -1.275; d2 = -2 1.275 |d1 = 1.275; d2 = 1 See also:`dfix(), floor(), ceil() `Function Libraries` 4 - 34 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` dsgn(MATH) dsgn(MATH) This function obtains the integer sign of a double. _____________________________________________________________ | | | `#include ` | | `int dsgn( argx );` | | `double argx;` | | | | argx - is the double for which the sign is desired.| |_____________________________________________________________| Description This function returns AS AN INTEGER, the state of the sign of the argument. Return Code The returned value will be minus one (-1) if argx is negative, zero (0) if argx is zero, and plus one (1) if argx is positive other than zero. Example #include stdio.h #include math.h char inbuf[81]; double d1; int sign; main() { puts("Dsgn: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; sign = dsgn(d1=atod(inbuf)); printf("d1 = %g; sign = %d\n",d1,sign); } } Dsgn: enter your number: EOF to exit -3.75 |d1 = -3.75; sign = -1 0 |d1 = 0; sign = 0 14.7e-15 |d1 = 1.47e-14; sign = 1 See also:`fsgn() `Function Libraries` 4 - 35 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` dtoa(MATH) dtoa(MATH) This function converts a double to string form in "e" notation. _____________________________________________________________ | | | `#include math.h` | | `char *dtoa( argx, string );` | | `double argx;` | | | | argx - is the double to convert to string form. | | | | string - is a character array of length 14 | |_____________________________________________________________| Description This function will convert a double to string form using the format: sd.ddddddEnee where "s" represents a sign character (blank or minus), "d" represents a decimal digit, "n" represents an exponent sign (plus or minus), and "e" represents an exponent decimal digit. Return Code A pointer to the string is returned so that the function may be used as a "string" argument. Example #include stdio.h #include math.h char string[14]; main() { double loop; for (loop=1.25e1; loop < 10.0e1; loop+=2.75e1) puts(dtoa(loop,string)); } 1.250000E+01 4.000000E+01 6.750000E+01 9.500000E+01 See also:`sprintf() `Function Libraries` 4 - 36 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` dup(LIBC); dup2(LIBC) dup2(LIBC); dup(LIBC) These functions duplicate an open file descriptor. _____________________________________________________________ | | | `int dup( fildes );` | | `int fildes;` | | | | `int dup2( fildes , fildes2);` | | `int fildes, fildes2;` | | | | fildes - is the file descriptor to duplicate. | | | | fildes2 - is the file descriptor to use for the | | duplication of fildes. | |_____________________________________________________________| Description These two functions allocate another file descriptor synonymous with the original. The "fildes" argument must be a file descriptor obtained from an open() or creat() call or one of the standard file descriptors: STDIN, STDOUT, or STDERR. The dup() function will search for a file descriptor to utilize, if one is available. The dup2() function will reuse the descriptor passed as the fildes2 argument. If fildes2 refers to an already opened file, that file will first be closed prior to duplicating the requested descriptor. Return Code EOF will be returned if the fildes argument passed is invalid or there are no more file descriptors left available. In either case, the global error variable, errno, will contain the UNIX error number associated with the error. Example #include stdio.h char message[] = "Writing to dup'd file descriptor\n"; main() { int fildes; if (( fildes = dup(STDOUT))==EOF) { fputs("dup() error\n",stderr); exit(-1); } write(fildes,message,strlen(message)); } Writing to dup'd file descriptor See also:`creat(), fcntl(), open(), perror(), write() `Function Libraries` 4 - 37 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` execl(LIBC) execl(LIBC) This function exits the program and causes execution of a command string built from the argument list. _____________________________________________________________ | | | `int execl(path, arg0, arg1, ..., argn, 0);` | | `char *path, *arg0, *arg1, ..., *argn;` | | | | path - is a pointer to the name of the program | | which is to be invoked. | | | | argx - are pointers to character strings which | | will be constructed as arguments to the | | program being invoked. | |_____________________________________________________________| Description The execl() function will build a command string composed of the path name and the arguments passed to execl(). Files in the current program will remain open unless the close_on_exec flag is set [see fopen()]. The current program then terminates and the resulting command string is passed to the DOS for execution. Conventionally, the "arg0" argument is the same as the path name. Return Code If the resulting command string would exceed the length supported by the DOS, execl() will return EOF and the global error variable, errno, will be set to E2BIG; otherwise, execl() will not return. Example #include stdio.h char path[]="dir", arg0[]="dir", arg1[]="sys:0", arg2[]="(sys,inv,a=)"; main() { puts("Test of execl()\n"); if (execl(path,arg0,arg1,arg2,0)==EOF) puts("DOS command line is too long"); } Test of execl() Drive :0 VR0005A 153 Cyl, Hard, Free = 732.00K/ 2448.00K, Date 12-Apr-85 SYS0/SYS SIP SYS1/SYS SIP+ SYS10/SYS SIP SYS11/SYS SIP SYS12/SYS SIP SYS13/SYS SIP SYS2/SYS SIP SYS3/SYS SIP SYS4/SYS SIP SYS5/SYS SIP SYS6/SYS SIP SYS7/SYS SIP SYS8/SYS SIP SYS9/SYS SIP SYSTEM/JCL + SYSUAF/DAT P+ See also:`execv(), cmdi() `Function Libraries` 4 - 38 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` execovl(IN) execovl(IN) This function is used to invoke an overlay of the executing C program. _____________________________________________________________ | | | `int execovl(ovnum, ovargc, ovargv);` | | `char ovnum; int ovargc; char *ovargv[];` | | | | ovnum - the requested overlay number in ASCII. | | | | ovargc - the quantity of args to be passed to the | | overlay in the ovargv array. | | | | ovargv - a pointer to the argument vector which is | | to be passed to the overlay. | |_____________________________________________________________| Description The execovl() function is used to invoke an overlay where a program environment has been developed around a root module and one or more overlay modules. The arg vector "ovargv" MUST have ovargc pointers in it. The "ovargc" and "ovargv" will be passed as arguments to the overlay's ovmain() function in that order. Note that "ovargc" and "ovargv" are optional. The generation of the root and overlay files requires the use of the MLINK linker provided with the MRAS assembler development system. Since the design of a C program environment which uses overlays is a complex procedure, its details will be discussed in the "Advanced Topics" chapter. Return Code A NULL will be returned if the requested overlay executed, otherwise EOF will be returned and errno will be appropriately set. Note that any return code from ovmain() is ignored; you can use public memory location(s) in the root for communications from the overlay. Example /* OVTEST/CCC - sample test root module */ extern int execovl(), printf(); int ovargc = 3; char *ovargv[3] = { "ovtest", "this is overlay" }; main() { ovargv[2] = "1"; if (execovl('1', ovargc, ovargv)) error(); ovargv[2] = "2"; if (execovl('2', ovargc, ovargv)) error(); } error() { perror("ovtest"); exit(1); } /* OVERLAYT/CCC - sample overlay for OVTEST */ ovmain(argc, argv) int argc; char *argv[]; { printf("%s: %s %s\n", argv[0], argv[1], argv[2]); } `Function Libraries` 4 - 39 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` execv(LIBC) execv(LIBC) This function exits the program and causes execution of a command string built from the array of pointers to strings. _____________________________________________________________ | | | `int execv(path, argv);` | | `char *path, *args[];` | | | | path - is a pointer to the name of the program | | which is to be invoked. | | | | args[] - are pointers to null-terminated character | | strings which will be used as arguments | | to the program being invoked. | |_____________________________________________________________| Description The execv() function will build a command string composed of the path name and the arguments passed to execv(). The array of pointers is terminated with a NULL pointer. Files in the current program will remain open unless the close_on_exec flag is set [see fopen()]. The current program then terminates and the resulting command string is passed to the DOS for execution. Conventionally, args[0] is the same as the path name. Return Code If the resulting command string would exceed the length supported by the DOS, execv() will return EOF and the global error variable, errno, will be set to E2BIG; otherwise, execl() will not return. Example #include stdio.h char *args[] = {"dir","zzzzz","(n)",0 }; main() { puts("Test of execv()\n"); if (execv(args[0],args)==EOF) puts("Command line too long!"); } Test of execv() Drive :0 VR0005A 153 Cyl, Hard, Free = 732.00K/ 2448.00K, Date 12-Apr-85 Drive :1 VR0005B 153 Cyl, Hard, Free = 598.00K/ 2448.00K, Date 12-Apr-85 Drive :2 FIXES02 40 Cyl, DDEN, Free = 130.50K/ 180.00K, Date 05-Sep-85 Drive :3 MCTEST05 40 Cyl, DDEN, Free = 169.50K/ 180.00K, Date 06-Nov-85 Drive :6 VR0006A 153 Cyl, Hard, Free = 428.00K/ 2448.00K, Date 23-Sep-85 Drive :7 VR0006B 153 Cyl, Hard, Free = 1520.00K/ 2448.00K, Date 23-Sep-85 See also:`execl(), cmdi() `Function Libraries` 4 - 40 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` exit(LIBC); _exit(LIBC) _exit(LIBC); exit(LIBC) This function is used to exit your program and return to DOS. _____________________________________________________________ | | | `void exit( retcod);` | | `int retcod;` | | | | `void _exit( retcod );` | | `int retcod;` | | | | retcod - is the return code to be passed to the DOS. | |_____________________________________________________________| Exit() and _exit() allow the user to exit cleanly from a program and control the consequences of exiting. Passing a zero (0) for the "retcod" argument to exit() indicates normal program termination, causing exit() to take the DOS normal exit. If a non-zero retcod is passed, exit() will take the error entry into DOS, thus aborting any Job Control Language processing in effect. If the terminating program was invoked by the system() function, the value passed to exit() will be the value returned to the calling program from system(). An exception is if a negative value is passed to exit(), in which case a negative one (-1) is returned to cmd(). Exit() closes all open files before returning to DOS; the _exit() func- tion does not. MC generates an automatic exit(0) when the terminating brace of main() is reached; thus, your program need not explicitly call exit() at that point. Return Code Exit() does not return to the caller. Warnings For compatibility with other C language systems, the programmer should not depend on exit() to close the program's files (other than standard I/O files). See also:`close(), fclose() `Function Libraries` 4 - 41 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` exp(MATH) exp(MATH) This function obtains the exponential of a double. _____________________________________________________________ | | | `#include ` | | `double exp( argx );` | | `double argx;` | | | | argx - is the double for which the exponential is | | desired. | |_____________________________________________________________| Description Exp() returns the exponential function of x (e raised to the x power). Return Code If the resulting value would overflow, exp() returns HUGE_VAL and the global error variable, errno, is set to ERANGE. An error message indicating the overflow range error is printed to standard error output. This error handling may be changed by the use of matherr(). Example #include stdio #include math char inbuf[81]; double d1,d2; main() { puts("Exp: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; d2 = exp(d1=atod(inbuf)); printf("d1 = %g; d2 = %g; errno = %d\n",d1,d2,errno); } } Exp: enter your number: EOF to exit 1.0 |d1 = 1; d2 = 2.71828; errno = 0 14.8 |d1 = 14.8; d2 = 2.67645e+06; errno = 0 150 |overflow range error |d1 = 150; d2 = 1.70141e+38; errno = 71 See also:`log(), matherr(), errno `Function Libraries` 4 - 42 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fabs(MATH) fabs(MATH) This function obtains the absolute value of a double. _____________________________________________________________ | | | `#include ` | | `double fabs( argx );` | | `double argx;` | | | | argx - is the double for which the absolute value | | is desired. | |_____________________________________________________________| Description This function returns the absolute value of its argument (i.e if argx is positive, argx is returned; if argx is negative, -argx is returned). Return Code The absolute value is returned. Example #include stdio #include math char inbuf[81]; double d1,d2; main() { puts("Fabs: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; d2 = fabs(d1=atod(inbuf)); printf("d1 = %g; d2 = %g; errno = %d\n",d1,d2,errno); } } Fabs: enter your number: EOF to exit 1.675384692 |d1 = 1.67538; d2 = 1.67538; errno = 0 -13.47e-3 |d1 = -0.01347; d2 = 0.01347; errno = 0 See also:`abs(), fabsf(), labs() `Function Libraries` 4 - 43 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fabsf(MATH) fabsf(MATH) This function is used to obtain the absolute value of a float. _____________________________________________________________ | | | `#include ` | | `float fabsf( xval );` | | `float xval;` | | | | xval - is the float whose absolute value is to be | | determined. | |_____________________________________________________________| Description This is a non-standard function which will obtain the absolute value of a float. For portability, use the equivalent construct: (float)fabs((double)xval); See also:`abs(), fabs(), labs() `Function Libraries` 4 - 44 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fatn(MATH) fatn(MATH) This function is used to obtain the arc tangent of a float. _____________________________________________________________ | | | `#include ` | | `float fatn( xval );` | | `float xval;` | | | | xval - is the float whose arc tangent is to be | | determined. | |_____________________________________________________________| Description This is a non-standard function which will obtain the arc tangent of a float. For portability, use the equivalent construct: (float)atan((double)xval); See also:`atan(), atan2(), ftan() `Function Libraries` 4 - 45 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fclose(LIBC) fclose(LIBC) This function is used to close a file opened with fopen(). _____________________________________________________________ | | | `int fclose( stream );` | | `FILE *stream;` | | | | stream - the file pointer obtained from fopen(). | |_____________________________________________________________| Fclose() is used to close an open file and to free the File Control Area (FCA) and file buffer for later use. The stream file pointer passed to fclose must have been obtained from fopen(). In the MC file system, exit() also closes files; however, the programmer should use fclose() on files opened by the program to ensure compatibility and portability. There is a limited number of files (determined by the MAXFILES compiler option), including standard files, that may be open at one time. Fclose() is used to free FCAs so an unlimited number of files may be accessed one after the other. Return Code The return code will be NULL if no error was detected in the closing operation (i.e. a successful close). If an error was detected during the close operation, then EOF will be returned and the global error variable, errno, will contain the UNIX error number associated with the error. Warnings The return code convention under MC follows the UNIX Seventh Edition and UNIX System V convention. As such, the return codes for success and failure are opposite as that returned under LC. Example if ( lastc!=0x1a ) putout(0x1a); fclose(fp1); fclose(fp2); puts("Files now closed"); exit(0); See also:`fcntl(), fdopen(), fopen(), freopen(), fflush() `Function Libraries` 4 - 46 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fcntl(LIBC) fcntl(LIBC) This function provides certain control over files. _____________________________________________________________ | | | `#include ` | | `int fcntl( fildes, cmd, arg );` | | `int fildes, cmd; "varying type" arg; | | | | fildes - is the file descriptor of the file you wish | | to control. | | | | cmd - is the specific fcntl() command (see text). | | | | arg - is specific to the fcntl() command. | |_____________________________________________________________| Description Fcntl() provides for certain control over open files. The file descrip- tor which identifies the file is one obtained from creat(), dup(), dup2(), fcntl(), open(), or one of the standard I/O devices: 0, 1, or 2. The "cmd" argument directs fcntl() to a specific operation. The commands available to fcntl() are defined in the "fcntl" header file, and are as follows: F_DUPFD This command will duplicate the file associated with fildes and return a new file descriptor having the following characteristics: - is the lowest numbered available file descriptor greater than or equal to "arg"; - is the same open file as fildes; - has the same access mode as fildes (read, write, or read/write); - the close_on_exec flag associated with the new file descriptor is reset to keep the file open upon execution of execl() or execv() invocations. F_GETFD This command will get the status of the close_on_exec flag. If the low-order bit is a 0, the file will remain open across execl() and execv() calls; otherwise, the file will be closed upon execution of execl() or execv(). F_SETFD This command will set the close_on_exec flag associated with fildes to the state of the low-order bit of arg, 0 or 1. F_GETFL This command obtains the file status flags (O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, O_CREAT, O_TRUNC) identified in the "fcntl" header file. `Function Libraries` 4 - 47 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` F_SETFL This command permits you to set the file status flags according to "arg". You may only change the following flags: O_RDONLY, O_WRONLY, or O_RDWR. Return Code If fildes is invalid, or if the argument passed as "arg" to F_SETFL is invalid, or if there is no new available file descriptor to return for the F_DUPFD command, EOF will be returned and the global error variable, errno, will contain the UNIX error number associated with the error. Example #include stdio.h #include fcntl.h struct { int mask; char *name; } oflags[] = { {O_RDONLY,"read_only"}, {O_WRONLY,"write_only"}, {O_RDWR,"read_write"}, {O_NDELAY,"delay"}, {O_APPEND,"append"}, {O_CREAT,"creat"}, {O_TRUNC,"truncate"}, {O_EXCL,"exclusive"} }; char *path="default/txt:7", sbuf[81], *itob(); main(argc,argv) int argc; char *argv[]; { int fildes, i, oflag; if (argc==2) path=argv[1]; if ((fildes=open(path,O_RDWR|O_CREAT,0777))==EOF) { printf("Can't open %s\n",path); exit(-1); } else printf("Opened %s; fildes = %d\n",path,fildes); oflag = fcntl(fildes,F_GETFL,NULL); fputs("oflags = ",stdout);puts(itob(oflag,sbuf)); for (i=0; i<8; i++) if (oflag&oflags[i].mask) { putchar(' '); fputs(oflags[i].name,stdout); } printf("\nc-o-e flag is %d\n",fcntl(fildes,F_GETFD,NULL)&1); close(fildes); } Opened default/txt:7; fildes = 3 oflags = 100100 read_write creat c-o-e flag is 1 See also:`dup(), dup2() `Function Libraries` 4 - 48 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fcos(MATH) fcos(MATH) This function is used to obtain the cosine of a float. _____________________________________________________________ | | | `#include ` | | `float fcos( xval );` | | `float xval; | | | | xval - is the float expressed in radians whose | | cosine is to be determined. | |_____________________________________________________________| Description This non-standard function will obtain the single precision cosine of its argument. For portability, use the equivalent form: (float)cos((double)xval); See also:`acos(), asin(), fsin(), ftan(), sin(), tan() `Function Libraries` 4 - 49 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fdopen(LIBC) This function is used to associate a stream with an open file descriptor. _____________________________________________________________ | | | `FILE *fdopen( fildes, type );` | | `char *fspec, mode;` | | | | fildes - is the file descriptor of the open file. | | | | type - is a character string which indicates the | | access mode chosen from the following: | | "r", "w", "a", "r+", "w+", or "a+". | |_____________________________________________________________| Description Fdopen() allows the programmer to initiate stream access of a given access type to a file opened with creat(), dup(), dup2(), fcntl(), or open(). "Fildes" is the file descriptor of the already opened file. "Type" points to a null-terminated string which defines the mode of access and must agree with the access specified when the file was opened. The allowable modes of access, which may be entered in upper or lower case, are: "r" - open for reading; "w" - truncate or create for writing; "a" - append; open for writing at the end of the file, or create for writing; "r+" - open for update (reading and writing); "w+" - truncate or create for update; "a+" - append; open or create for update (appending) at the end of the file. When a file is opened for update, both reading and writing may be per- formed on the stream; however, writing may not be immediately followed by reading without an intervening fseek() or rewind(), and reading may not be followed by writing without an intervening fseek(), rewind(), or an input operation which encounters an end-of-file [first cleared by cleareof()]; Note that fdopen() is similar to fpup() in that a stream pointer asso- ciated with a file descriptor is returned; however, fdopen() permits you to alter the access mode of the stream. Return Code The stream file pointer is returned if no errors are detected in the fdopen() operation. If fildes does not refer to an open file descriptor or the access type requested does not agree with the access of the open file, NULL (zero) will be returned and the global error variable, errno, will con- tain the UNIX error number associated with the error. `Function Libraries` 4 - 50 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Warnings When a file is opened for append, the file is positioned so that the first output operation will write to the end of the file. The output func- tions do not perform this positioning operation; therefore, do not use rewind() or fseek() with streams to which you wish to append. Example #include stdio.h extern FILE *fdopen(); char message[] = "This is written to fdopen'd stream"; main() { FILE *stream; if (!(stream=fdopen(STDOUT,"w"))) { puts("fdopen error"); exit(-1); } puts(message,stream); fclose(stream); } This is written to fdopen'd stream See also:`fopen(), freopen() `Function Libraries` 4 - 51 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fdown(LIBC) fdown(LIBC) This function is used to convert a stream file pointer to a file descriptor. It is identical to fileno(). _____________________________________________________________ | | | `int fdown( stream );` | | `FILE *stream;` | | | | stream - the file pointer of the stream. | |_____________________________________________________________| Description Sometimes it may be useful to cross between file stream I/O functions and block device I/O functions which use file descriptors. Since file streams are referenced with file pointers and block device files are referenced with file descriptors, the fdown() function may be used to obtain the file de- scriptor given a stream file pointer. Return Code If the stream file pointer is recognized as being invalid, EOF will be returned; otherwise, the needed file descriptor will be returned. Warning The stream file pointer passed as the argument of fdown() must be one obtained from fopen(), fdopen(), or the file pointer of a standard device (i.e. stdin, stdout, stderr). Example if (fd2 = fcntl( fdown(stdin),F_DUPFD,3)) == EOF) abend(NULL); if (fdown(stderr) != STDERR) abend("internal error"); See also:`fileno(), fpup() `Function Libraries` 4 - 52 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` feof(LIBC) feof(LIBC) This function is used to determine if the end-of-file has been sensed. _____________________________________________________________ | | | `int feof( stream );` | | `FILE *stream;` | | | | stream - the file pointer obtained from fopen(). | |_____________________________________________________________| Description This function obtains the status of the EOF flag maintained in the File Control Area for an open file. Return Code If an end-of-file had been previously encountered, feof() will return a non-zero value; otherwise, NULL will be returned. Example #include stdio.h main() { int c; FILE *fp; if ((fp=freopen("tfeof/ccc","r",stdin))==NULL) { perror("main: freopen error"); exit(-1); } while ((c=getchar())!= EOF) putchar(c); puts( feof(stdin) ? "EOF received" : "no EOF yet"); printf("DOS error number is %d\n",ferror(stdin)); if (ferror(stdin)) perror("main"); } EOF received DOS error number is 0 See also:`ferror(), clearerr(), cleareof() `Function Libraries` 4 - 53 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ferror(LIBC) ferror(LIBC) This function is used to obtain the last DOS I/O error number associated with a file stream. _____________________________________________________________ | | | `int ferror( stream );` | | `FILE *stream;` | | | | stream - the file pointer obtained from fopen(). | |_____________________________________________________________| Description The MC file system maintains the number of the last error code associ- ated with a file stream or file. This error code may be recovered via the ferror() function. When an error occurs, the global error variable, errno, will contain the UNIX error number associated with the DOS error. Consult your DOS manual for the meaning of each DOS error code. Return Code If no error has been encountered, NULL will be returned. If the file pointer references a closed file, then EOF will be returned. Otherwise, the return code will be the DOS error code. Warnings The stream file pointer passed as the argument to the function must be one obtained from fopen() or the stream pointer of any standard device (i.e. stdin, stdout, stderr). The error number storage is shared with the ungetc() one character buffer; thus, an ungetc() on the stream may wipe out the error number obtainable via ferror(). Example #include stdio.h main() { int c; FILE *fp; if ((fp=freopen("tfeof/ccc","r",stdin))==NULL) { perror("main: freopen error"); exit(-1); } while ((c=getchar())!= EOF) putchar(c); puts( feof(stdin) ? "EOF received" : "no EOF yet"); printf("DOS error number is %d\n",ferror(stdin)); if (ferror(stdin)) perror("main"); } EOF received DOS error number is 0 See also:`perror() `Function Libraries` 4 - 54 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fexp(MATH) fexp(MATH) This function obtains the exponential of a float. _____________________________________________________________ | | | `#include ` | | `float fexp( argx );` | | `float argx;` | | | | argx - is the float for which the exponential is | | desired. | |_____________________________________________________________| Description The non-standard function, fexp(), returns the exponential function of x (e raised to the x power) of the single precision argument (i.e. a float). For portability, use the equivalent construct: (float)exp((double)argx); See also:`flog(), exp(), log() `Function Libraries` 4 - 55 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ffix(MATH) ffix(MATH) This function obtains the truncated value of a float. _____________________________________________________________ | | | `#include ` | | `float ffix( argx );` | | `float argx;` | | | | argx - is the float value to truncate. | |_____________________________________________________________| Description The truncated value is obtained by dropping all digits to the right of the decimal point so the result is a whole number. If argx is negative, ffix(argx) is equivalent to fint(x)+1.0. This is a nonstandard function. For portability, use the equivalent construct: (float)dfix((double)argx); See also:`fint(), dfix, dint(), floor(), ceil() `Function Libraries` 4 - 56 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fflush(LIBC) fflush(LIBC) This function is used to force a physical write of any buffered output to an output file stream and update the DOS directory. _____________________________________________________________ | | | `int fflush( stream );` | | `FILE *stream;` | | | | stream - the file pointer obtained from fopen(). | |_____________________________________________________________| Description When program crashes occur, some output data written to a file stream may have been buffered in the stream's I/O buffer and not written to disk. The file's directory information also may not get updated. The fflush() function can be used to complete all physical output and update the stream's directory without actually closing the file (if invoked prior to such a pro- gram crash). Return Code The return code will be NULL if no error occurs during the flushing operation. If an error is detected, EOF will be returned and the global error variable, errno, will contain the UNIX error number associated with the error. Example #include char message[] = "Testing, 1, 2, 3... Hello, test\n"; main() { FILE *stream, *fopen(); if ((stream=fopen("testfile/dat:7","w"))==NULL) { perror("fopen error"); exit(-1); } fputs(message,stream); fputs(message,stream); if (fflush(stream)==EOF) perror("fflush error"); puts("Program terminating through _exit()"); _exit(); /* simulate error terminate w/o closing files */ } Program terminating through _exit() DOS Ready list testfile/dat:7 Testing, 1, 2, 3... Hello, test Testing, 1, 2, 3... Hello, test See also:`fopen(), fclose(), putc(), fwrite() `Function Libraries` 4 - 57 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fgetc(LIBC) fgetc(LIBC) This function is used to obtain a character from a file stream. _____________________________________________________________ | | | `int fgetc( stream );` | | `FILE *stream;` | | | | stream - is the file pointer of the stream | |_____________________________________________________________| Description Fgetc() is used to input a single byte from a file stream. The MC library treats fgetc() as equivalent to getc(): both are functions. Return Code The return code is the integer value of the character input from the stream. If an end of file is encountered, then "EOF" (-1) is returned. Warning If the value returned by the function is to be stored before testing for end-of-file, it must be stored in an integer variable and not a char. If not, the end of file value will be truncated and will remain undetected, as a char of -1 does not equal an int of -1. Example #include filecopy(fp) FILE *fp; { int c; while ((c = fgetc(fp)) != EOF) if (c != fputc(c,stdout)) abort("Output file write error"); } See also:`getc(), getchar(), getw() `Function Libraries` 4 - 58 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fgets(LIBC) fgets(LIBC) This function is used to get a buffered line from a file stream. _____________________________________________________________ | | | `char *fgets( buf, maxlen, stream);` | | `char *buf; int max; FILE *stream;` | | | | buf - is a pointer to the character buffer. | | | | maxlen - is the maximum length of the input string. | | | | stream - is the stream pointer obtained from fopen().| |_____________________________________________________________| Description Fgets() is used to obtain a buffered line from a file. A file may be the console keyboard, the RS-232 interface, or any input device or disk file. Up to (maxlen) bytes will be placed in the buffer. Input is terminated when either a newline or end of file is encountered or maximum buffer size is reached. The newline character is not stripped from the input. For compatibility with DOS Job Control Language files, keyboard line input is performed using the @KEYIN system call. Fgets() recognizes the BREAK key as the end of file from the keyboard if the O_BREAK flag is set via the option() function. Also, the maximum number of keyboard characters accepted for input will be the minimum of (maxlen,255). Return Code If an error is encountered, NULL will be returned and the global error variable, errno, will contain the UNIX error number associated with the error; otherwise, a pointer to "buf" is returned. Example #include stdio.h main() { int i; FILE *stream, *fopen(); char buffer[81]; if ((stream=fopen("testfile/dat:7","w+"))==NULL) { perror("fopen error"); exit(-1); } for (i=1; i<9999; i*=10) fprintf(stream,"Record %d is here\n",i); rewind(stream); while ((fgets(buffer,80,stream))!=NULL) fputs(buffer,stdout); } Record 1 is here Record 10 is here Record 100 is here Record 1000 is here See also:`fputs(), gets(), puts() `Function Libraries` 4 - 59 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fill(LIBC) fill(LIBC) This function will propagate a character throughout a memory region. _____________________________________________________________ | | | `void fill( buffer, count, cval );` | | `char *buffer, cval; int count;` | | | | buffer - is the address pointing to the start of the | | memory region you wish to populate. | | | | count - is the number of bytes to populate. | | | | cval - is the character to populate throughout the | | region of memory. | |_____________________________________________________________| Description The fill() function will propagate the character, "cval", into the mem- ory "buffer" for "count" bytes. If "cval" is passed as an integer value, the low-order byte is used for the propagation. Warning Note that although the fill() function is contained in LIBC, it is not a standard function. For purposes of portability across C compilers, use the equivalent standard function, memset(). Example char *getmem(size) unsigned size; { if (!(mptr=alloc(size)) return NULL; fill(mptr,size,NULL); return mptr; } See also:`memset() `Function Libraries` 4 - 60 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fint(MATH) fint(MATH) This function is used to obtain the integer part of a float. _____________________________________________________________ | | | `#include ` | | `float fint( xval );` | | `float xval;` | | | | xval - is the float whose integer part is to be | | determined. | |_____________________________________________________________| Description This is a non-standard function which will obtain the integer part of a float. For portability, use the equivalent construct: (float)floor((double)xval); See also:`floor(), ffix() `Function Libraries` 4 - 61 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` flog(MATH) flog(MATH) This function is used to obtain the natural log of a float. _____________________________________________________________ | | | `#include ` | | `float flog( xval );` | | `float xval;` | | | | xval - is the float whose log is to be determined. | |_____________________________________________________________| Description This is a non-standard function which will obtain the natural logarithm (base e) of a float. For portability, use the equivalent construct: (float)log((double)xval); See also:`log(), fexp() `Function Libraries` 4 - 62 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` floor(MATH) floor(MATH) This function obtains the integer part of a double. _____________________________________________________________ | | | `#include math.h` | | `double floor( argx );` | | `double argx;` | | | | argx - is the double for which the integer part | | is desired. | |_____________________________________________________________| Description This function obtains the largest integer not greater than "argx". Example #include stdio #include math char inbuf[81]; double d1,d2; main() { puts("floor: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; d2 = floor(d1=atod(inbuf)); printf("d1 = %g; d2 = %g\n",d1,d2); } } floor: enter your number: EOF to exit -1.275 |d1 = -1.275; d2 = -2 1.275 |d1 = 1.275; d2 = 1 See also:`dfix(), dint(), ceil() `Function Libraries` 4 - 63 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fmod(MATH) fmod(MATH) This function is used to perform a floating point modulo division. _____________________________________________________________ | | | `#include ` | | `double fmod( xval, yval );` | | `double xval, yval;` | | | | xval - is the double numerator. | | | | yval - is the modulo divisor. | |_____________________________________________________________| Description Fmod() returns the floating point remainder of the division of xval by yval. Zero is returned if xval is zero or if xval/yval would overflow. Example #include stdio.h #include math.h main() { double numer, denom; for ( numer=10.1, denom=3.0; numer>0.0; numer--) printf("%g ",fmod(numer,denom)); } 1.1 0.1 2.1 1.1 0.1 2.1 1.1 0.1 2.1 1.1 0.1 `Function Libraries` 4 - 64 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fopen(LIBC) fopen(LIBC) This function is used to open a file or device for stream I/O. _____________________________________________________________ | | | `FILE *fopen( path, type );` | | `char *fspec, mode;` | | | | path - points to a character string which con- | | contains the specification of the file. | | | | type - is a character string which indicates the | | access mode chosen from the following: | | "r", "w", "a", "r+", "w+", or "a+". | |_____________________________________________________________| Description Fopen() allows the programmer to initiate access to a file. Except for standard input, output, and error files which are automatically opened, all files must be opened using fopen() [or various other file opening functions]. "Path" points to a file specification string identifying the file to open. "Type" points to a null-terminated string which may be in upper or lower case and which defines the mode of access . The allowable modes are: "r" - open for reading; "w" - truncate or create for writing; "a" - append; open for writing at the end of the file, or create for writing; "r+" - open for update (reading and writing); "w+" - truncate or create for update; "a+" - append; open or create for update (appending) at the end of the file. The file pointer is used whenever access to the opened file is needed. If zero is returned, an error occurred during the open process. When a file is opened for update, both reading and writing may be per- formed on the stream; however, writing may not be immediately followed by input without an intervening fseek() or rewind(), and reading may not be followed by writing without an intervening fseek(), rewind(), or an input operation which encounters an end-of-file [first cleared by cleareof()]; Return Code The stream file pointer is returned if no errors are detected in the open operation. If an error is detected during the open operation, NULL (zero) will be returned and the global error variable, errno, will contain the UNIX error number associated with the error. Warnings Opening the same file for both input and output with two or more calls to fopen() should NOT be done. If the file is accessed in this manner, it `Function Libraries` 4 - 65 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` will create unpredictable results, possibly causing loss of file integrity. A file may be "fopened" for both read and write using the "r+", "w+", or "a+" access modes. When a file is opened for append, the file is positioned so that the first output operation will write to the end of the file. The output func- tions do not perform this positioning operation; therefore, do not use rewind() or fseek() on streams to which you wish to append. Example getfile(path) char *path; { FILE *fp; if ((fp=fopen(path,"r")) == NULL) { printf("Open error - %-20s\n",path); exit(); } else return fp; } Numerous other illustrations of fopen() appear in the many other examples throughout this chapter. See also:`fclose(), fdopen(), freopen(), open() `Function Libraries` 4 - 66 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fprintf(LIBC); fprintf(MATH) fprintf(MATH); fprintf(LIBC) These functions create a formatted image for output. _____________________________________________________________ | | | `#include ` ...optional | | `int fprintf( stream, control, arg1, arg2, ...);` | | `FILE *stream; char *control; args SEE TEXT` | | | | stream - is the stream file pointer for output. | | | | control - is a string containing transparent printing | | characters and conversion specifications. | | | | argn - are arguments to be formatted for the out- | | put print image as specified by the control.| |_____________________________________________________________| Description The fprintf() function is used to write a formatted output image to a file stream identified by the "stream" file pointer. The function contained in LIBC does not include support for "e", "f", or "g" translation formats. The math library package includes a version of fprintf() which supports all standard format translations and is accessible when your program includes the preprocessor directive, "#include ". The specifications for formatting the output are determined by the character string, "control". This string will contain ordinary characters copied directly to the output image and/or specifications denoting the field conversions of all arguments. The conversion specifications take the form of: %{flags}{width}{.prec}char As can be noted, the specification is a sequence of sub-fields of which the percent sign (%) and the "char" are mandatory if variables are to be printed. The percent is an "escape" character signaling the start of the field spec- ification. The "char" denotes the format of the output field image {binary, decimal, string, etc.}. The sub-field specifications are interpreted as follows: conversion initiator %` - the translation specification initiator; flags space`- specifies that the result of a signed conversion will always start with a minus sign or space ('-' or ' '); -` - specifies that the value will be left-justified within the print field image, otherwise it will be right-justified; +` - specifies that the result of a signed conversion will `Function Libraries` 4 - 67 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` always start with a sign ('+' or '-'); #` - specifies that the value is to be converted to an alternate form. 'c', 'd', 's', and 'u' conversions ignore this flag. For 'o' conversions, the precision is increased to force the first digit to be a zero. For 'b' or 'B' conv- conversions, a non-zero value will be preceded with either '0b' or '0B'. For 'x' or 'X' conversions, a non-zero value will be preceded with '0x' or '0X'. For 'e', 'E', 'f', 'g', and 'G' conversions, the output will always contain a dec- imal point. Finally, for 'g' or 'G' translations, trailing zeroes will not be removed; width specifier width`- specifies the minimum width of the print field image. If the converted value has fewer characters than this value, it will be padded right or left with a pad character which will be a blank unless the field-width begins with a zero, in which case the pad character will be a zero. If the converted value has more characters than the width, then it (the width) is adjusted to hold the full result. precision specifier .prec`- specifies the maximum number of string bytes for 's' translation, the maximum number of digits to the right of the decimal point for 'e', 'E', or 'f' translation, the number of significant digits in 'g' or 'G' translation, or the minimum number of digits in a 'b', 'B', 'd', 'o', 'u', 'x', or 'X' translation (the field will be left padded with zeroes); generally called the "precision". conversion type h` - specifies that the following 'b', 'B', 'd', 'o', 'u', 'x', or 'X' translation applies to a short integer; l` - specifies that the following 'b', 'B', 'd', 'o', 'u', 'x', or 'X' translation applies to a long integer; char` - the conversion character [b=B=binary, o=octal, d=decimal, x=X=hexadecimal, s=string, c=character, u=unsigned, e=E=float] of the format, "[-]d.dddesdd" or "[-]d.dddEsdd", with the number of d's after the decimal point according to the precision (default of 6), [f=float] of the format, "[-]ddd.dd", with the number of d's after the decimal point equal to the precision (default of 6); [g=G=float] printed with format "d", "f", 'e', or "E" whichever gives full precision in minimum space. A field width or precision may also be indicated by an asterisk ('*') instead of a digit string. When this is the case, an integer argument must then be supplied which contains the value of the precision. A negative value will be interpreted as invoking the '-' left justification. The integer `Function Libraries` 4 - 68 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` argument must immediately precede the argument corresponding to the value to be translated in the argument list. Any portion of the control string which cannot be interpreted as a con- version specification field is considered to be transparent printing charac- ters and will be passed directly to the print image. Warnings Single precision float arguments must be explicitly casted to double if you are using the "+f" compiler option as the print formatter always assumes a floating point variable to be double precision. A string longer than 32767 characters will be truncated. A width not in the range of a short int will fail. The precision must be in the positive range of a short int. Return Code If an output error is detected, EOF will be returned; otherwise, the number of characters actually printed will be returned. Example fprintf(stderr,"%d characters, %d lines were copied\n",bytes,lines); See also:`fscanf(), printf(), sprintf() `Function Libraries` 4 - 69 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fpup(LIBC) fpup(LIBC) This function obtains the stream pointer of a file descriptor. _____________________________________________________________ | | | `FILE *fpup( fildes);` | | `int fildes;` | | | | fildes - the file descriptor of the file. | |_____________________________________________________________| Description Sometimes it may be useful to cross between file stream I/O and file I/O. Since file streams are referenced with file pointers and files are referenced with file descriptors, the fpup() function may be used to obtain the stream file pointer given the file's descriptor. Return Code Fpup() will return NULL on an invalid file descriptor. Example if ( seek(fd1, block, 3)) == EOF) { err_num = ferror( fpup(fd1)); printf("Error %d detected on file %d\n",err_num,fd1); } See also: fdown(), fdopen(), fileno() `Function Libraries` 4 - 70 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fputs(LIBC) fputs(LIBC) This function will output a string to a file/device. _____________________________________________________________ | | | `int fputs( string, stream );` | | `char *string; FILE *stream;` | | | | string - is the address of the string to be output. | | | | stream - is the file pointer of the output file. | |_____________________________________________________________| Description Fputs() outputs to the file defined by "stream", all characters pointed to by "string", up to the first NULL byte. This function does not append any new-line character to the string. Return Code If an error was detected, fputs() will return EOF and the global error variable, errno, will contain the UNIX error number associated with the error; otherwise, NULL will be returned. Warning Calling fputs() with an invalid file pointer can result in destruction of files or other havoc. Example #include stdio.h main() { int i; FILE *stream, *fopen(); char buffer[81]; if ((stream=fopen("testfile/dat:7","w+"))==NULL) { perror("fopen error"); exit(-1); } for (i=1; i<9999; i*=10) fprintf(stream,"Record %d is here\n",i); rewind(stream); while ((fgets(buffer,80,stream))!=NULL) fputs(buffer,stdout); } Record 1 is here Record 10 is here Record 100 is here Record 1000 is here See also:`fgets(), puts() `Function Libraries` 4 - 71 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fraise(MATH) fraise(MATH) This function is the float equivalent of pow(). _____________________________________________________________ | | | `#include ` | | `float fraise( argx, argy );` | | `float argx, argy;` | | | | argx - is the base value to be raised. | | | | argy - is the power of the base value. | |_____________________________________________________________| Description This function will raise a single precision number to a single precision power. It is equivalent to: (float)pow((double)argx,(double)argy); Return Code See also:`lpower(), pow() `Function Libraries` 4 - 72 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fread(LIBC) fread(LIBC) This function reads "n" items into an array from a stream input. _____________________________________________________________ | | | `int fread( ptr, size, nitems, stream );` | | `char *ptr; int size, nitems; FILE *stream;` | | | | ptr - is a pointer to the receiving array. | | | | size - is the size of an element in bytes. | | | | nitems - is the number of items to read. | | | | stream - is a stream pointer from which to read. | |_____________________________________________________________| Description This function will read into the array pointed to by "ptr", "nitems" elements of data from the file stream defined by "stream". Each element will be of size "size". It is sometimes convenient to use the "sizeof" operator in determining the size of an element. This is illustrated in the example. Return Code The number of items actually read are returned. A NULL will be returned if "size" or "nitems" is less than or equal to zero. If an error occurs and no data items are read, you can use feof() or ferror() to discriminate be- tween an error return or a "zero" input. Example #include stdio.h main() { char days[12]; FILE *stream; int i; if ((stream=fopen("boot/sys.lsidos","r"))==NULL) { perror("fopen error"); exit(-1); } fseek(stream,0x202L,0); /* seek stream to days_in_month data */ fread(days,sizeof(char),sizeof days,stream); for (i=0; i<12; i++) printf("%d ",days[i]); fclose(stream); } 31 28 31 30 31 30 31 31 30 31 30 31 See also:`fwrite() `Function Libraries` 4 - 73 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` free(LIBC) free(LIBC) This function frees memory allocated with alloc(), malloc(), calloc(), or realloc(). _____________________________________________________________ | | | `void free( ptr );` | | `char *ptr;` | | | | ptr - pointer to a block previously allocated. | |_____________________________________________________________| Description Free() is called when a memory block allocated to the program by any of the memory allocating functions [alloc(), calloc(), malloc(), or realloc()] is no longer needed, and the programmer wishes to free the memory space for later use. "ptr" points to the first (lowest) byte allocated to the program and is the pointer returned by the allocating function. Warning Calling free() with an address other than that obtained from a call to alloc(), calloc(), malloc(), or realloc() may cause unpredictable results. If the pointer passed to free() is outside the scope of the dynamic heap, free() will report an error. Since free() is used by the standard I/O facility, the error will be reported directly to the system's output device to avoid cir- cular errors. Example #include "stdio.h" static int (*_compar)(); static char *_base, *pivot; static unsigned _width; extern char *malloc(), *move(); extern void free(); static void _sort(), _swap(); int qsort(base, nel, width, compar) char *base; int (*compar)(); unsigned nel, width; { if (! (pivot = malloc(width))) return EOF; _compar = compar; _base = base; _width = width; _sort(0, --nel); free(pivot); return 0; } See also:`alloc(), calloc(), malloc(), realloc() `Function Libraries` 4 - 74 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` freemem(IN) freemem(IN) This obtains the size of the largest block of memory which can be allocated to your program immediately following the function call. _____________________________________________________________ | | | `#option INLIB` | | `unsigned freemem();` | |_____________________________________________________________| Description Freemem() returns the maximum amount of memory which can be obtained from alloc(), calloc(), or malloc() at the time of the call to freemem(). The figure is obtained by taking the maximum of (a) the largest unused block kept in the free list available for reuse and (b) the amount of memory above the program break [reduced by approximately 1K less bytes than actual to account for reserved program stack space and function linkage overhead]. Example #option INLIB #define BLOCK 5000 char *ram[10] = {0,0,0,0,0,0,0,0,0,0}; main() { int i; unsigned core_left, core_now; char *alloc(); core_left = freemem(); printf("Beginning core left = %u\n",core_left); for ( i=0 ; (ram[i]=alloc(BLOCK))&&i<10 ; i++ ) printf("%u ",freemem()); putchar('\n'); while (i) { if (ram[--i]) free(ram[i]); core_now = freemem(); printf("%u ",core_now); } } Beginning core left = 41772 36770 31766 26762 21758 16754 11750 6746 1742 6744 11748 16752 21756 26760 31764 36768 41772 See also`alloc(), free() `Function Libraries` 4 - 75 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` freopen(LIBC) freopen(LIBC) This function substitutes a named file in lieu of an open stream. _____________________________________________________________ | | | `FILE *freopen( path, type, stream );` | | `char *path, *type; FILE *stream;` | | | | path - points to a character string which con- | | contains the specification of the file. | | | | type - is a character string which indicates the | | access mode chosen from the following: | | "r", "w", "a", "r+", "w+", or "a+". | | | | stream - is the stream file pointer to "reopen". | |_____________________________________________________________| Description Freopen() substitutes the named file denoted by "path" in place of the already opened stream designated by the file pointer, "stream". The original stream is closed, regardless of whether the open actually succeeds. The function will return a pointer to the new stream. The freopen() function is typically used to attach the standard I/O streams to files other than the opened standard devices so that the stream I/O functions such as putchar(), getchar(), puts(), gets(), printf(), scanf(), etc., may be utilized. "Type" points to a null-terminated string which defines the mode of access and may be in upper or lower case. The allowable modes are: "r" - open for reading; "w" - truncate or create for writing; "a" - append; open for writing at the end of the file, or create for writing; "r+" - open for update (reading and writing); "w+" - truncate or create for update; "a+" - append; open or create for update (appending) at the end of the file. When a file is opened for update, both reading and writing may be per- formed on the stream; however, writing may not be immediately followed by input without an intervening fseek() or rewind(), and reading may not be followed by writing without an intervening fseek(), rewind(), or an input operation which encounters an end-of-file [first cleared by cleareof()]; Return Code The stream file pointer to be used in accessing the file is returned if no errors are detected in the open operation. If an error is detected during the open operation, NULL will be returned and the global error variable, errno, will contain the UNIX error number associated with the error. `Function Libraries` 4 - 76 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Warnings When a file is opened for append, the file is positioned so that the first output operation will write to the end of the file. The output func- tions do not perform this positioning operation; therefore, do not use rewind() or fseek() on a stream to which you wish to append. Example getfile(fname) char *fname; { FILE *fp; extern FILE *freopen(); if ((fp=freopen(fname,"r",stdout)) == NULL) { fprintf(stderr,"Open error - %-20s\n",fname); exit(); } else return fp; } See also:`fopen(), fdopen() `Function Libraries` 4 - 77 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` frexp(MATH) frexp(MATH) This function separates a double into its mantissa and exponent. _____________________________________________________________ | | | `#include ` | | `double frexp( value, eptr );` | | `double value; int *eptr;` | | | | value - is the double value to separate. | | | | eptr - is a pointer_to_int to receive the exponent.| |_____________________________________________________________| Description Double precision floating point numbers may be written as a fractional part, x, times an integer power, n, of the base, 2; where x is in the range [0.5 <= x < 1.0]. The frexp() function separates a double into the "x" fractional part and the integer "n" exponent of base_2. The function returns the fractional part and stores the integer exponent into the location pointed to by the integer pointer, eptr. Thus, the following relationship is true: mantissa = frexp(value,&exponent); value = pow(2.0,(double)exponent) * mantissa; Return Code The fractional part of the double is returned. If "value" is zero, both the fractional part and the exponent are 0. Example #include stdio.h #include math.h char inbuf[81]; double d, v, m; int e; main() { puts("frexp: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; m = frexp(d=atod(inbuf),&e); v = pow(2.0,(double)e) * m; printf("d = %g = %g; e = %d; m = %g; errno = %d\n",d,v,e,m,errno); } } frexp: enter your number: EOF to exit 2 |d = 2 = 2; e = 1; m = 1; errno = 4 4 |d = 4 = 4; e = 2; m = 1; errno = 4 4.75 |d = 4.75 = 4.75; e = 3; m = 0.59375; errno = 4 5.8e4 |d = 58000 = 58000; e = 16; m = 0.88501; errno = 0 0 |d = 0 = 0; e = 0; m = 0; errno = 0 See also:`ldexp(), modf() `Function Libraries` 4 - 78 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` frnd(MATH) frnd(MATH) This function obtains a float random number. _____________________________________________________________ | | | `#include ` | | `float frnd( value );` | | `float value;` | | | | value - used to determine the range of the result. | |_____________________________________________________________| Description This function will return a floating point single precision (a float) random number. If "value" is 0.0, a number between greater than or equal to zero but less than 1.0 will be returned. If "value" is non-negative and is in the range 1-32767, the returned random number will be in the range 1.0 through fint(value) inclusive. Random number If "value" is negative, frnd() will return "value" and errno will be set to DOMAIN. This error condition may be trapped by the use of a _fltvec(). See also:`errno, fseed(), srand(), rand() `Function Libraries` 4 - 79 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fscanf(LIBC); fscanf(MATH) fscanf(MATH); fscanf(LIBC) These functions are used to scan a formatted print image, interpret the image fields according to a control string, and store the translated results in the arguments passed in the function's invocation. _____________________________________________________________ | | | `#include ` ... optional | | `int fscanf( stream, control, arg1, arg2, ... );` | | `FILE *stream; char *control; args SEE TEXT` | | | | stream - is the stream file pointer to read. | | | | control - as documented below. | | | | args - as required to match the control string. | |_____________________________________________________________| Description The fscanf() function is the input analog of the fprintf() function. It provides similar translations; however, the conversions are from ASCII string fields to argument values. Fscanf() inputs from the file stream identified by "stream". The arguments identified as "arg1, arg2, ..." MUST BE POINTERS, rather than values since the scan function stores the converted results into the arguments. The control string may contain: (1) White space characters [0x20, or 0x09 through 0x0d] which are ignored, (2) Ordinary characters other than '%' which are expected to match the next non-white space character of the input stream, (3) A conversion specification consisting of the character '%', an optional assignment suppression character '*', an optional decimal number specifying a maximum field width, an optional letter "l" or "h" indicating the size of the receiving variable (i.e. long or short), and a conversion character. An input field is defined as a string of non-white space characters extending to either the next white space or until the field width is exhausted, which- ever comes first. The conversion specification directs the conversion of the next input field. If assignment suppression is indicated by the '*', the in- put field is skipped over and no argument should be passed in the function's invocation. The scan function reads across new-lines ('\n') since they are considered to be white space. The conversion characters supported are: d - A decimal integer is expected. It may be preceded by '+' or '-'. o - An octal integer is expected. It does not require the leading zero. x - A hexadecimal integer is expected. `Function Libraries` 4 - 80 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` b - A binary integer is expected. c - A single character is expected. The normal skip-over-white-space is suppressed so that the next character is input and assigned. If you want to assign the next non-white space character, specify "%1s". If any other width is specified, that many characters will be input and assigned to the pointed to character array of sufficient size. s - A character string is expected. The assignment will be terminated with a NULL ('\0'). f - A floating point number is expected. The conversion character 'e' is interpreted the same as 'f'. Preceding the 'e' or 'f' with an 'l' indicates a double rather than a float. The input format for a float is an optional sign, a string of decimal digits possibly containing a decimal point, an optional exponent field containing an 'e' or 'E' followed by a signed decimal integer. NOTE: In this implementation, the scan function will not terminate if an invalid character is detected in the float string. The assigned float value will be that which is translated up to the offending character. n - Specifies that the number of characters scanned up to that point will be returned in the corresponding argument; scanning will continue. [ - Indicates string data to be matched against the following set of char- acters which are called the "scanset". Note also that the normal skip over whitespace is suppressed. The scanset designates the list of per- missable characters to be acceptable in the input string. The scanset follows the left bracket and is terminated by a right bracket ("]"). A range of characters is entered as "abcdefg". This can also be entered as "a-g" as in 'first'-'last' where the 'first' character of the range is lexically less than the 'last' character of the range. A dash is accepted as a member of the scanset if it is either the first character in the scanset, the last character in the scanset, or the character preceding it is lexically greater than the character following it. A right bracket ("]") may be included in the scanset if it is the first character fol- lowing the left bracket. If a circumflex ("^") is the first character of the scanset, it indicates that the scanset is actually composed of all characters not in the following list; thus, it serves to complement the given list. For example, "[^a-z]" indicates that the scanset is to be composed of all characters which are not lower-case. If a right bracket or dash is to be "excluded" from such a list, it must immediately follow the circumflex. The scanset is selected from the ASCII character set only. The input will be terminated when a whitespace character is input, a character not in the scanset is input, or the maximum field width specification is exhausted. The corresponding receiving argument must be large enough to hold the data field and the terminating NULL which will be automatically appended. The 'f' [and likewise the 'e'] translation will not be supported unless the preprocessor statement, "#option MATHLIB" or "#include ", is inserted in your C source module or the MATH library is manually searched first during the linking process. `Function Libraries` 4 - 81 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Any characters remaining in the input stream that were not accepted in- cluding any offending terminating character will still be available to the next scan invocation [assuming no intervening use of the input file stream]. Return Code If end-of-file is reached during the input, EOF will be returned. Otherwise, the function's return value will be equal to the number of suc- cessfully matched and assigned input items. Example #include #include main() { char achar, string[81]; double f1; int n_items, aint; n_items = fscanf(sfp1,"%c%3d%*2d%6s%lf",&achar,&aint,string,&f1); printf("Count = %d |%c %d %s %e\n",n_items,achar,aint,string,f1); } For input of: a12345abcdef 12.345e5 Prints : Count = 4 |a 123 abcdef 1.2345E+06 See also:`scanf(), sscanf() `Function Libraries` 4 - 82 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fseed(MATH) fseed(MATH) This function seeds the random number generator fetched by frnd(). _____________________________________________________________ | | | `#include ` | | `float fseed( seed );` | | `float seed;` | | | | seed - is the new seed value. | |_____________________________________________________________| Description This function seeds the single precision random number generator with a known value. Return Code The function returns the old seed value. See also:`frnd(), srand(), rand() `Function Libraries` 4 - 83 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fseek(LIBC) fseek(LIBC) This function is the stream equivalent of lseek(). _____________________________________________________________ | | | `int fseek( stream, offset, ptrname );` | | `FILE *stream; long offset; int ptrname;` | | | | stream - is the stream file to re-position. | | | | offset - is the signed new position of the stream. | | | | ptrname - specifies seek from beginning, current | | position, or the end of the stream. | |_____________________________________________________________| Description This function sets the next input or output operation on the identified stream to occur at the position designated. The new position is the signed distance away from the beginning, current position, or end of the file stream depending on whether "ptrname" is 0, 1, or 2. Fseek() will undo the effect of any ungetc() on the associated stream. Note that you cannot fseek() a tty device! Return Code Fseek returns non-zero for improper seeks, otherwise NULL. Example #include stdio.h main() { char days[12]; FILE *stream; int i; if ((stream=fopen("boot/sys.lsidos","r"))==NULL) { perror("fopen error"); exit(-1); } fseek(stream,0x202L,0); /* seek stream to days_in_month data */ fread(days,sizeof(char),sizeof days,stream); for (i=0; i<12; i++) printf("%d ",days[i]); fclose(stream); } 31 28 31 30 31 30 31 31 30 31 30 31 See also:`ftell(), isatty(), lseek(), rewind(), seek() `Function Libraries` 4 - 84 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fsgn(MATH) fsgn(MATH) This function obtains the integer sign of a float. _____________________________________________________________ | | | `#include ` | | `int fsgn( value );` | | `float value;` | | | | value - is the float whose sign is desired. | |_____________________________________________________________| Description Fsgn() obtains the status as to whether the value is negative, zero, or positive. Return Code Fsgn() returns an integer value less than zero, equal to zero, or greater than zero, depending on whether the argument value is less than 0.0, equal to 0.0, or greater than 0.0. See also:`dsgn() `Function Libraries` 4 - 85 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fsqr(MATH) fsqr(MATH) This function obtains the square root of a float. _____________________________________________________________ | | | `#include ` | | `float fsqr( value );` | | `float value;` | | | | value - is the float whose square root is desired. | |_____________________________________________________________| Description This function is non-standard. It obtains the square root of a float and is equivalent to: (float)sqrt((double)value); Return Code See also:`sqrt() `Function Libraries` 4 - 86 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` fstat(LIBC) fstat(LIBC) This function obtains the file status of an open file. _____________________________________________________________ | | | `#include ` | | `int fstat( fildes, buf );` | | `int fildes; struct stat *buf;` | | | | fildes - is the file descriptor of the file to stat. | | | | buf - is a pointer to the structure which will be | | filled with the file's status. | |_____________________________________________________________| Description This function obtains a great deal of information concerning the open file known by "fildes". The data structure is defined in the stat header file and is as follows: struct stat { dev_t st_dev; /* device # - (DEC/DRV or Device name) */ ino_t st_ino; /* index node - unused in MC */ unsigned short st_mode; /* modes - see #define */ short st_nlink; /* # of file links - unused */ short st_uid; /* User ID - MC uses 16-bit user pswd */ short st_gid; /* Group ID - MC uses 16-bit owner pswd */ dev_t st_rdev; /* unused */ off_t st_size; /* Size of file in bytes */ time_t st_atime; /* time last read - unused in MC */ time_t st_mtime; /* time last written - MOD date */ time_t st_ctime; /* attribute change, mtime - unused */ }; Masks for the "st_mode" field are defined in the header file and are: S_IFMT 0170000 /* type of file - mask */ S_IFDIR 0040000 /* directory - set if DIR/SYS */ S_IFCHR 0020000 /* character special - set if device */ S_IFBLK 0060000 /* block special - set if SYS */ S_IFREG 0100000 /* regular - set for files */ S_IFMPC 0030000 /* multiplexed char special - unused */ S_IFMPB 0070000 /* multiplexed block channel - unused */ S_ISUID 0004000 /* set user id on execution - unused */ S_ISGID 0002000 /* set group id on execution - unused */ S_ISVTX 0001000 /* save swapped text - unused */ S_IREAD 0000400 /* read permission, owner */ S_IWRITE 0000200 /* write permission, owner */ S_IEXEC 0000100 /* execute/search permission, owner */ S_GREAD 0000040 /* read permission, group */ S_GWRITE 0000020 /* write permission, group */ S_GEXEC 0000010 /* execute/search permission, group */ S_UREAD 0000004 /* read permission, user */ S_UWRITE 0000002 /* write permission, user */ `Function Libraries` 4 - 87 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` S_UEXEC 0000001 /* execute/search permission, user */ Return Code Upon a successful completion of the function, NULL is returned; other- wise, EOF is returned and errno will contain the UNIX error number which describes the error. Example (a piece of sortsym/ccc) #include struct stat stat; unsigned short nrecs, fsize, i; char tempname[NAMELEN], tempaddr[ADDRLEN]; union record { struct { char name[NAMELEN]; char space; char addr[ADDRLEN]; char newline; } byname; struct { char addr[ADDRLEN]; char space; char name[NAMELEN]; char newline; } byaddr; } *record, *base, **prec, **recp; void abend(); extern int fstat(), extern char *alloc(); extern unsigned short read(), write(); main(argc, argv) int argc; char *argv[]; { if (fstat(0, &stat) == EOF) exit(1); /* stat the input file (stdin) */ nrecs = (fsize = (unsigned short) stat.st_size - 1) / RECLEN; if (stat.st_size > 0xffffL || ! (base = (RECORD *) alloc(fsize)) || ! (prec = (RECORD **) alloc(nrecs * sizeof(RECORD *)))) abend("SYM file too large\n"); if (read(0, (char *) base, fsize) != fsize) exit(1); /* read SYM file */ See also:`creat(), open() `Function Libraries` 4 - 88 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ftan(MATH) ftan(MATH) This function obtains the trigonometric tangent of a float. _____________________________________________________________ | | | `#include ` | | `float ftan( value );` | | `float value;` | | | | value - is the float whose tangent is desired. | |_____________________________________________________________| Description This function obtains the trigonometric tangent of its single precision floating point argument which must be in radians. It is equivalent to: (float)tan((double)value); See also:`tan() `Function Libraries` 4 - 89 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ftell(LIBC) ftell(LIBC) This function obtains the relative position of a stream. _____________________________________________________________ | | | `long ftell( stream );` | | `FILE *stream;` | | | | stream - is the stream file pointer. | |_____________________________________________________________| Description This function returns the position, as a long integer, of the stream for the next character I/O operation. The position is relative to the beginning of the stream. Return Code The current position relative to the beginning of the stream is returned as a long integer. Example #include stdio.h extern int errno; extern long ftell(); main() { void abend(); errno = 0; if (isatty(STDIN)) abend("Can't fseek() a character device"); if (fseek(stdin,0x1a05L,0)) abend("fseek() error 1"); if (fseek(stdin,0x333L,1)) abend("fseek() error 2"); printf("Current positition after seeks is %lx\n",ftell(stdin)); } void abend(s) char *s; { printf("%s: errno = %d\n",s,errno); exit(-1); } tftell:3 Can't fseek() a character device: errno = 0 DOS Ready tftell:3 key may be optioned to be interpreted as an end-of-file condition by means of the option() function. This provides a means to indicate an EOF for character devices not normally having the capability to generate the EOF indication. Return Code The return code is the integer value of the character input from the stream. If an end of file is encountered, then "EOF" (-1) is returned. Warning If the value returned by the function is to be stored before testing for end-of-file, it must be stored in an integer variable and not a char. If not, the end of file value will be truncated and will remain undetected as a char of -1 does not equal an int of -1. Examples #include filecopy(fp) /* copy a file to the standard output */ FILE *fp; { int c; while ((c = getc(fp)) != EOF) if (c != putc(c,stdout)) abend("Output file write error"); } bytes = lines = 0; while( (c=getchar()) != EOF ) { putchar(c); ++bytes; if ( c==EOL ) ++lines; } See also:`gets(), putc(), putchar(),scanf() `Function Libraries` 4 - 94 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` gets(LIBC) gets(LIBC) This function fetches (inputs) a buffered line from standard input. _____________________________________________________________ | | | `char *gets( buffer );` | | `char *buffer;` | | | | buffer - a pointer to a character array of length 81.| |_____________________________________________________________| Description Gets() inputs a line up to 80 characters long from the standard input (stdin) and places the line in memory starting at the address given by "buf- fer". The input will terminate on an error or if a new-line character is input. The new-line is discarded and the string is terminated by NULL. If you do not want to have the new-line character discarded, use the near-equivalent form, fgets(buffer,80,stdin);. Note that if stdin is not the keyboard device and the input line is longer than 80 characters, it will be split; any part not accepted will be fetched by the next request for input from stdin. Return Code If an error is encountered during the input, or end-of-file is reached, the return code will be NULL (0); otherwise, buffer will be returned. Warnings The "buffer" must be at least 81 characters long. Example #include stdio.h char buffer[81], string[10]; main() { int i; fputs("Enter your string: ",stdout); gets(buffer); for ( i=0; i` | | `double hypot( argx, argy );` | | `double argx, argy;` | | | | argx, argy - are the two required elements. | |_____________________________________________________________| Description The Euclidian distance is calculated according to the formula: hypot = sqrt( argx*argx + argy*argy ) Example #include stdio.h #include math.h main() { double x, y; for (x=3.0,y=4.0; x<7.0; x++, y++) printf("x = %g, y = %g, hypot(x,y) = %g\n",x,y,hypot(x,y)); } x = 3, y = 4, hypot(x,y) = 5 x = 4, y = 5, hypot(x,y) = 6.40312 x = 5, y = 6, hypot(x,y) = 7.81025 x = 6, y = 7, hypot(x,y) = 9.21954 See also:`sqrt() `Function Libraries` 4 - 98 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` index(LIBC) index(LIBC) This function obtains the position of the first occurrence of a speci- fied character within a string. It is identical to strchr(), its UNIX System V counterpart. _____________________________________________________________ | | | `char *index( s, c );` | | `char *s; int c;` | | | | s - is a pointer to the source string. | | | | c - is the character to find. | |_____________________________________________________________| Description The index() function will look for the first occurrence of character 'c' in the string pointed to by "s". The low-order byte of the integer, 'c', will be used as the character. Index will operate properly when 'c' is the NULL character. Return Code If the character 'c' is not found in string "s", NULL will be returned; otherwise, a pointer to the position of 'c' in "s" will be returned. Example #include stdio.h main() { char *pos, buffer[81], *fgets(), *index(); puts("Enter your string; EOF to exit"); while (gets(buffer)) { if (!(pos=index(buffer,'r'))) printf("'r' not found in [%s]\n? ",buffer); else printf("'r' is character %d in [%s]\n? ",pos-buffer+1,buffer); } } Enter your string; EOF to exit abcdefghijklmnop 'r' not found in [abcdefghijklmnop] ? zyxwvutsrqponmlkjihgfedcba 'r' is character 9 in [zyxwvutsrqponmlkjihgfedcba] ? abcdefghijklmnopqrstuvwxyz 'r' is character 18 in [abcdefghijklmnopqrstuvwxyz] ? See also:`strcat(), strchr(), strcpy(), strcspn(), strncat(), strncpy(), strpbrk(), strrchr(), strspn() `Function Libraries` 4 - 99 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` inkey(IN) inkey(IN) The inkey() function scans the DOS keyboard device (*KI). _____________________________________________________________ | | | `#option INLIB` | | `int inkey();` | |_____________________________________________________________| Description The inkey() function makes a single scan of the keyboard and returns the ASCII value of any depressed key. It will return a zero if no key is pressed. Note that it will always scan the physical keyboard regardless of any MC standard input redirection. Warning Inkey() cannot return a NULL character. Example #include stdio.h #option INLIB /* needed for automatic search if IN/REL */ #define CTL_C 0x03 extern char *ctime(); unsigned long counter = 0L; main() { long clock; time(&clock); fputs(ctime(&clock),stdout); while (TRUE) /* simulate some long processing loop */ { ++counter; if (inkey() == CTL_C) break; } printf("Counter got to %ld\n",counter); time(&clock); fputs(ctime(&clock),stdout); } Tue Nov 19 10:30:33 1985 Counter got to 9204 Tue Nov 19 10:30:44 1985 See also:`checkc(), getchar() `Function Libraries` 4 - 100 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` inport(IN) inport(IN) This function reads a machine port. _____________________________________________________________ | | | `#option INLIB` | | `int inport( port );` | | `int port;` | | | | port - is the designated machine port to read. | |_____________________________________________________________| Description The function, inport(), returns as an integer, the value read from the specified port. Example #include stdio.h #option INLIB /* needed to automatically search IN/REL */ #define FDC 0xf0 main() { int fdc[4], i; for (i=3; i>=0; i--) fdc[i] = inport(FDC+i); printf("FDC: data = %02x, sector = %02x, track = %02x, status = %02x\n"\ ,fdc[0],fdc[1],fdc[2],fdc[3]); } FDC: data = 00, sector = 15, track = 03, status = 00 See also:`outport() `Function Libraries` 4 - 101 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ioctl(LIBC) ioctl(LIBC) This function performs various controlling operations on character special files (devices). _____________________________________________________________ | | | `#include sgtty.h` | | `int ioctl( fildes, request, argp );` | | `int fildes, request; struct sgttyb *argp;` | | | | fildes - is a descriptor of the file. | | | | request - is the desired operation code. | | | | argp - is a pointer to the data structure. | |_____________________________________________________________| Description This function allows you to control certain characteristics about a file. The data acted upon is stored in the data structure pointed to by the "argp" argument and is obtained from an invocation of ioctl() using the TIOCGETP request. Once you modify the data, it is presented to the device handler via the TIOCSETP request. The data structure is defined in the "sgtty" header file and is as follows: struct sgttyb { char sg_colctr; /* column counter */ char sg_control; /* control byte */ char sg_flag; /* FCA flag byte */ }; The "sgttyb.sg_colctr" element stores a counter for the current column posi- tion of the output image for the device. This item is relative to zero. The "sgttyb.sg_control" byte stores various bit fields and is masked as follows: IO_BREAK 0x10 /* mask for #option BREAK */ IO_TABSTOP 0x0f /* mask for "tabstop-1" */ IO_FDCOE 0x80 /* mask for "close_on_exec" flag */ Return Code If the call was successful, NULL will be returned; otherwise, an EOF will be returned and the global error variable, errno, will contain the UNIX error number associated with the error. `Function Libraries` 4 - 102 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Example #include stdio.h #include sgtty.h #define TABSTOP 3 int c; main() { static struct sgttyb sg = { 0,0 }; if (ioctl(STDOUT,TIOCGETP,&sg)) fputs("Error from ioctl\n",stderr); else { sg.sg_control &= ~IO_TABSTOP; /* strip current tab stop */ sg.sg_control |= TABSTOP; /* set new tab stop */ ioctl(STDOUT,TIOCSETP,&sg); } while (((c=getchar())!= EOF) && (c==putchar(c))) ; } See also:`gtty(), stty() `Function Libraries` 4 - 103 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` iswhat(LIBC) iswhat(LIBC) These are a series of functions which perform character type tests. _____________________________________________________________ | | | `int iswhat( c );` | | `char c;` | | | | iswhat - replaced by the test function name. | | | | c - the character under test. | |_____________________________________________________________| Description The following functions will return TRUE when the character under test matches the test range: function character range for a TRUE condition -------- ------------------------------------------ isalnum A-Z, a-z, 0-9 isalpha A-Z, a-z isascii 0x00-0x7f _isbdigit 0,1 iscntrl 0x00-0x1f, 0x7f isdigit 0-9 islower a-z _isodigit 0-7 isprint 0x20-0x7e ispunct 0x20-0x2f, 0x3a-0x40, 0x5b-0x60, 0x7b-0x7e isspace 0x20, 0x09-0x0d isupper A-Z isxdigit 0-9, A-F, a-f Return Code If the character does not match the test range, FALSE will be returned. Example if ( isdigit(char)) printf("Character is <0-9>\n"); else if ( islower(char)) printf("Character is \n"); else if ( isupper(char)) printf("Character is \n"); else printf("Character is none of the above\n"); `Function Libraries` 4 - 104 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` isatty(LIBC) isatty(LIBC) This function determines if the designated file is character special. _____________________________________________________________ | | | `int isatty( fildes );` | | `int fildes;` | | | | fildes - is the descriptor of the file to check. | |_____________________________________________________________| Description Isatty() returns TRUE if the file descriptor refers to an open character special file (i.e. a character device). A FALSE condition is returned if the descriptor is invalid or does not refer to an open file. Return Code The return code is TRUE or FALSE as required. Example #include stdio.h extern int errno; extern long ftell(); main() { void abend(); errno = 0; if (isatty(STDIN)) abend("Can't fseek() a character device"); if (fseek(stdin,0x1a05L,0)) abend("fseek() error 1"); if (fseek(stdin,0x333L,1)) abend("fseek() error 2"); printf("Current positition after seeks is %lx\n",ftell(stdin)); } void abend(s) char *s; { printf("%s: errno = %d\n",s,errno); exit(-1); } tftell:3 Can't fseek() a character device: errno = 0 DOS Ready See also:`gtty(), ioctl(), stty(), ttyname() `Function Libraries` 4 - 105 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` itoa(LIBC); itob(LIBC); itoo(LIBC); itou(LIBC); itox(LIBC) ito?() These functions are used to convert integers to character strings of digits (binary, octal, decimal or hexadecimal). _____________________________________________________________ | | | `char *itoa( ival, string );` | | | | `char *itob( ival, string );` | | | | `char *itoo( ival, string );` | | | | `char *itou( ival, string );` | | | | `char *itox( ival, string );` | | `int ival; char string[];` | | | | ival - is an integer value to convert. | | | | string - is the resulting string of signed decimal, | | unsigned decimel, binary, octal, or | | hexadecimal digits for "?" equal to | | "a", "u", "b", "o", or "x" respectively. | |_____________________________________________________________| Description These standard C functions are used to convert integer values to their character string image. Functions are provided to deal with character strings containing binary, octal, decimal or hexadecimal digits. Return Code A pointer to the character string is returned. Example #include stdio.h char a[33], b[33], o[33], u[33], x[33]; int num = 100; main(argc,argv) int argc; char *argv[]; { if (argc==2) num = atoi(*++argv); itoa(num,a); itob(num,b); itoo(num,o); itou(num,u); itox(num,x); printf("num = %d: %sD %sB %sO %sU %sX\n",num,a,b,o,u,x); } num = 100: 100D 1100100B 144O 100U 64X num = -32768: -32768D 1000000000000000B 100000O 32768U 8000X num = 32767: 32767D 111111111111111B 77777O 32767U 7FFFX `Function Libraries` 4 - 106 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` labs(LIBC) labs(LIBC) This function is used to obtain the absolute value of a long integer. _____________________________________________________________ | | | `long labs( lval );` | | `long lval;` | | | | lval - is the long integer whose absolute value | | is to be determined. | |_____________________________________________________________| Description This function will obtain the absolute value of its long integer argument. If lval is negative, -lval will be returned. If lval is non-negative, lval will be returned. Example #include stdio.h char inbuf[81]; extern long labs(), atol(); main() { long num; puts("Enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; printf("Absolute value of %ld is %ld\n",num,labs(num=atol(inbuf))); } } Enter your number: EOF to exit -123456789 |Absolute value of -123456789 is 123456789 -276893105 |Absolute value of -276893105 is 276893105 987654321 |Absolute value of 987654321 is 987654321 See also:`abs(), fabs(), fabsf() `Function Libraries` 4 - 107 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ldexp(MATH) ldexp(MATH) This function multiplies a fractional value times two-to-an-exponent. _____________________________________________________________ | | | `#include ` | | `double ldexp( value, exp );` | | `double value; int exp;` | | | | value - the fractional part of a double. | | | | exp - the integer exponent of two. | |_____________________________________________________________| Description This function calculates a double floating point number composed of a fractional "value" and an integer exponent, "exp", of base 2. It is used in combining parts of a double floating point number. Return Code If the resulting value would overflow, +/- HUGE_VAL will be returned and errno will be set to ERANGE. If the result would cause underflow, 0 is returned and errno is set to ERANGE. Example #include stdio #include math char inbuf[81]; double d, v, m; int e; main() { puts("ldexp: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; m = frexp(d=atod(inbuf),&e); v = ldexp(m,e); printf("d = %g = %g; e = %d; m = %g; errno = %d\n",d,v,e,m,errno); } } ldexp: enter your number: EOF to exit 1234567 |d = 1.23457e+06 = 1.23457e+06; e = 21; m = 0.588687; errno = 0 -7.684e10 |d = -7.684e+10 = -7.684e+10; e = 37; m = -0.559085; errno = 0 1e40 |d = 1.70141e+38 = 1.70141e+38; e = 127; m = 1; errno = 3 See also:`frexp(), modf() `Function Libraries` 4 - 108 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` line(IN) line(IN) This function is used to plot a line of pixels on the CRT. _____________________________________________________________ | | | `#option INLIB` | | `int line( funcod, x1, y1, x2, y2 );` | | `int funcod, x1, y1, x2, y2;` | | | | funcod - an operation code to set (1) or reset (0) | | the pixels involved in the line. | | | | x1,y1 - the coordinate of the first point defining | | the line. | | | | x2,y2 - the coordinate of the second point defining | | the line. | |_____________________________________________________________| Description The "line()" function will plot a line connecting coordinate point (x1,y1) with coordinate point (x2,y2). Virtual Points A virtual points is any pixel that is part of the plot request which cannot appear on the CRT screen as it is out of the range of acceptable coordinate values. The line function permits your arguments to describe such "virtual" images; however, any portion of the geometric shape that would be outside of the CRT image area is not plotted. Return Code A minus one (-1) indicates that the coordinate points (x1,y1) or (x2,y2), or a portion of any plot is out of range (i.e. virtual and does not appear in the CRT image). A minus three (-3) will be returned if the function code passed is invalid (i.e. not in the range <0-1>). Example #option INLIB #define PLOT 1 #define ERASE 0 int x1,x2,y1,y2,t,t1; main() { for ( x1=0,y1=0,x2=127,t=0; t<=47; t++) { line(PLOT,x1,y1,x2,t); line(ERASE,x1,y1,x2,t); } for ( y2=47,t=127; t>=0; t--) { line(PLOT,x1,y1,t,y2); line(ERASE,x1,y1,t,y2); } } See also:`box(), circle(), ploc(), pmode(), point(), reset(), set() `Function Libraries` 4 - 109 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` localtime(LIBC) localtime(LIBC) This function obtains a pointer to the broken down time structure. _____________________________________________________________ | | | `#include ` | | `struct tm *localtime( clock );` | | `long *clock;` | | | | clock - is a pointer to the long integer containing | | the UNIX time. | |_____________________________________________________________| Description This function returns a pointer to the structure, tm (defined in the "time" header file), which will contain the broken down time based on the contents of the long integer pointed to by "clock". Note that localtime() is based on the actual time set in your machine and makes no automatic allowance for time zone or Daylight Savings Time. Return Code A pointer to the broken down time structure will be returned. Warning The pointer returned by localtime() points to local static storage which may be valid only immediately following the function call. Example #include stdio.h #include time.h extern struct tm *localtime(); extern long time(); struct tm *p; char *ps[4] = { "th","st","nd","rd" }; main() { long clock; int s; clock = time(NULL); p = localtime(&clock); if ((s = p->tm_yday % 10) > 3) s = 0; printf("At the tone, the time will be %d:%d:%d on the %d%s day of %d\n",\ p->tm_hour,p->tm_min,p->tm_sec,p->tm_yday,ps[s],p->tm_year+1900); system("date"); system("time"); } At the tone, the time will be 15:51:12 on the 323rd day of 1985 Tue, Nov 19, 1985 15:51:13 See also:`asctime(), ctime(), sysdate(), systime(), time() `Function Libraries` 4 - 110 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` log(MATH); log10(MATH) log10(MATH); log(MATH) These functions calculate the log of a double. _____________________________________________________________ | | | `#include "math.h" | | `double log( argx );` | | | | `double log10( argx );` | | `double argx;` | | | | argx - is the double for which the log or log10 | | is to be determined. | |_____________________________________________________________| Description The log() function obtains the natural log (base_e) of its argument. The log10() function takes the base_10 logarithm of its argument. In either case, the value of "argx" must be positive. Return Code Both log() and log10() return HUGE_VAL and set errno to EDOM when "argx" is not greater than zero. A message indicating DOMAIN error is printed on the standard error output device. This error handling may be changed via the matherr() function. Example #include stdio.h #include math.h char inbuf[81]; double d, le, l10; main() { puts("log: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; le = log(d=atod(inbuf)); l10 = log10(d); printf("d = %g; log = %g; log10 = %g; errno = %d\n",d,le,l10,errno); } } log: enter your number: EOF to exit 100 |d = 100; log = 4.60517; log10 = 2; errno = 0 2.7182818284590452 |d = 2.71828; log = 1; log10 = 0.434294; errno = 0 -5 |argument domain error |argument domain error |d = -5; log = -1.70141e+38; log10 = -1.70141e+38; errno = 70 See also:`exp(), pow(), sqrt(), matherr() `Function Libraries` 4 - 111 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` longjmp(LIBC) This function performs a long jump to an environment saved by setjmp(). _____________________________________________________________ | | | `#include ` | | `void longjmp( env, val );` | | `jmp_buf env; int val;` | | | | env - is the environment saved by setjmp(). | | | | val - is the value returned by setjmp(). | |_____________________________________________________________| Description A longjmp() will restore the program to the environment as saved in "env" by a previous call to setjmp(). After the longjmp() is completed, the program execution will continue as if the corresponding call to setjmp() had just occurred; however, the returned value will be the value passed as "val" in the longjmp() call, rather than zero. The setjmp()/longjmp() companion functions can be used in error control within nested functions so as to effect an escape from a lower-level function error without backtracking through error handling in each higher level nest. Example #include setjmp.h jmp_buf env; main() { int i, val; if (val=setjmp(env)) printf("Error %d on i=%d\n",val,i); else for (i=0;i<3;++i) { func1(i); printf("No error %d\n",i); } } func1(i) int i; { func2(i); } func2(i) int i; { func3(i); } func3(i) int i; { if (i<2) return; else longjmp(env,1); } See also:`setjmp() `Function Libraries` 4 - 112 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` lpower(LIBC) lpower(LIBC) This function is used to raise a long integer to a long integer power. _____________________________________________________________ | | | `long lpower( argx, argy );` | | `long argx, argy;` | | | | argx - is the base long integer to be raised to | | the argy power. | | | | argy - is the long integer exponent. | |_____________________________________________________________| Description Lpower() will raise a long integer, argx, to the long integer power, argy. Note that the result could overflow with relatively small values of argy; thus, exercise caution in the argument values. Return code If argy is not in the range 0L through 31L, the value returned will be zero and the global error variable, errno, will be set to ERANGE. Otherwise, the returned value will be argx raised to the argy power. Example #include stdio.h #define SET 1 long john, silver; extern long lpower(); main() { option(O_KBECHO,SET); puts("lpower: enter your numbers: EOF to exit"); while (TRUE) { if (scanf("%ld %ld",&john,&silver) != 2) break; printf("%ld to the %ld power = %ld\n",john,silver,lpower(john,silver)); } } lpower: enter your numbers: EOF to exit 2 20 |2 to the 20 power = 1048576 3 8 |3 to the 8 power = 6561 See also:`fraise(), pow() `Function Libraries` 4 - 113 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` lseek(LIBC) lseek(LIBC) This function is used to reposition a file. _____________________________________________________________ | | | `long lseek( fildes, offset, whence );` | | `int fildes, whence; long offset;` | | | | fildes - is a file descriptor obtained from open(), | | creat(), dup(), or fcntl(). | | | | offset - the new position relative to whence. | | | | whence - specifies offset from beginning, current, | | or end for origin equal to 0, 1, or 2. | |_____________________________________________________________| Description The lseek() function is used for random positioning in a file in prepa- ration for reading or writing. Offset is a signed long integer allowing you to seek to any relative character position in the file. Return Code Upon successful completion, the new position relative to the beginning of the file will be returned. If an error occurs during the seeking function, EOF (-1) will be returned and the global error variable, errno, will contain the UNIX error number associated with the error. The DOS error number may be obtained via ferror(fpup(fildes));. Warning Remember that "offset" is treated as a SIGNED long integer. Thus, a negative offset passed with an origin of 0 is an error. It is not an error to lseek past the end of a file. You cannot lseek() a tty device. Example #include stdio.h #include fcntl.h char string[58]; int fildes; main() { if ((fildes=open("boot/sys.lsidos",O_RDONLY))==EOF) { perror("open error"); exit(-1); } lseek(fildes,0x2c7L,0); /* seek date mnemonics */ read(fildes, string, 57); /* read them into string */ string[57] = '\0'; /* set NULL for string terminator */ puts(string); /* display the mnemonics */ close(fildes); /* close the file */ } SunMonTueWedThuFriSatJanFebMarAprMayJunJulAugSepOctNovDec See also:`feof(), fseek(), isatty(), rewind(), seek(), tell() `Function Libraries` 4 - 114 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ltoa(LIBC); ltob(LIBC); ltoo(LIBC); ltou(LIBC); ltox(LIBC) lto?() These functions are used to convert long integers to character strings of digits (binary, octal, decimal or hexadecimal). _____________________________________________________________ | | | `char *ltoa( lval, string );` | | | | `char *ltob( lval, string );` | | | | `char *ltoo( lval, string );` | | | | `char *ltou( lval, string );` | | | | `char *ltox( lval, string );` | | `long lval; char xstring[];` | | | | lval - is a long integer value to convert. | | | | string - is the resulting string of signed decimal, | | unsigned decimal, octal, decimal, or | | hexadecimal digits for lto? equal to "a", | | "u", "b", "o", "u", or "x" respectively. | |_____________________________________________________________| Description These standard C functions are used to convert long integer values to their character string image. Functions are provided to deal with character strings containing binary, octal, decimal or hexadecimal digits. Return Code In each case, a pointer to the resulting string is returned. Example #include stdio.h char a[33], b[33], o[33], u[33], x[33]; long num = 100000; extern long atol(); main(argc,argv) int argc; char *argv[]; { if (argc==2) num = atol(*++argv); ltoa(num,a); ltob(num,b); ltoo(num,o); ltou(num,u); ltox(num,x); printf("num = %ld: %sD %sB %sO %sU %sX\n",num,a,b,o,u,x); } num = 100000: 100000D 11000011010100000B 303240O 100000U 186A0X num = 65537: 65537D 10000000000000001B 200001O 65537U 10001X `Function Libraries` 4 - 115 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` malloc(LIBC) malloc(LIBC) This function is used to allocate a zeroed memory block. _____________________________________________________________ | | | `char *malloc ( size );` | | `unsigned size;` | | | | size - unsigned number of bytes needed. | |_____________________________________________________________| Description Malloc() is used to dynamically allocate memory during program execution. The complementary function, free(), is used to release memory allocated through malloc(). Malloc may be used to get table or buffer space when the amount of memory space available is unknown, or when the program needs to dynamically allocate space for an array. Return Code If a memory block has been allocated, the value returned is a pointer to the memory block (pointer to char). If insufficient memory is available to satisfy the allocation, a NULL will be returned. Warnings The program must not access memory outside of the area allocated. File access routines use dynamic allocation to establish and release File Control Areas (FCA's). The programmer cannot assume that memory not allocated is free for use, since later file opens may cause memory overlays. It is advised that the programmer always use the supplied dynamic allocation functions for memory accessing. Example symtbsz -= symtbsz % symsiz; /* make integral */ if ( !(symtab = malloc(symtbsz)) ) abend("not enough memory"); glbptr = startglb = symtab; See also:`alloc(), brk(), calloc(), realloc(), and sbrk() `Function Libraries` 4 - 116 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` memccpy(LIBC) memccpy(LIBC) This function will copy "n" characters in memory until character 'c' is detected. _____________________________________________________________ | | | `char *memccpy( s1, s2, c, n );` | | `char *s1, *s2; int c, n;` | | | | s1 - a pointer to the receiving memory area. | | | | s2 - a pointer to the originating memory area. | | | | c - the copy stops after the first occurrence | | of this character or until n characters. | | | | n - the number of characters to copy. | |_____________________________________________________________| Description This function will perform a copy of characters from the memory region pointed to by "s2" into the memory region pointed to by "s1", stopping after the first occurrence of character 'c' has been copied or after "n" characters have been copied, whichever comes first. Warning There is no checking on the magnitude of "n"; thus, a memccpy() with an erroneous value for "n" could overwrite a critical portion of memory. Over- lapping copies may produce unpredictable results. Return Code A pointer to the character after the copy of 'c' in "s1" is returned if 'c' was found; otherwise, a NULL pointer will be returned. See also:`memchr(), memcmp(), memcpy(), memset() `Function Libraries` 4 - 117 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` memchr(LIBC) memchr(LIBC) This function finds the first occurrence of a character in memory. _____________________________________________________________ | | | `char *memchr( s, c, n );` | | `char *s; int c, n;` | | | | s - a pointer to the memory region to search. | | | | c - is the character to look for. | | | | n - is the number of characters to search. | |_____________________________________________________________| Description This function will scan the memory region pointed to by "s" for "n" characters looking for the first occurrence of character 'c'. Return Code A pointer to the character 'c' will be returned if that character is found within the "n" bytes; otherwise, a NULL pointer will be returned. Example #include stdio.h extern char *memchr(); char *s = NULL, *t; int c; unsigned n = 0; main() { fputs("Enter the character to find: ",stdout); c = getchar(); while ( TRUE ) { if (!(t=memchr(s,c,n))) break; printf("Found %c at %04x (%c)\n",c,t,*t); n = n - ( ++t - s ); s = t; } } Enter the character to find: Found | at 033d (|) Found | at 0384 (|) Found | at 03ab (|) Found | at 058b (|) continued See also:`memccpy(), memcmp(), memcpy(), memset(). `Function Libraries` 4 - 118 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` memcmp(LIBC) memcmp(LIBC) This function will compare two regions of memory. _____________________________________________________________ | | | `int memcmp( s1, s2, n );` | | `char *s1, *s2; int n;` | | | | s1 - is a pointer to the first memory region. | | | | s2 - is a pointer to the second memory region. | | | | n - is the number of characters to compare. | |_____________________________________________________________| Description This function will compare "n" characters of memory region "s1" to memory region "s2" and returns an integer less than, equal to, or greater than 0, depending on whether the first n-characters of "s1" are lexicograph- ically less than, equal to, or greater than the first n-characters of "s2". Example #define SIZE 4096 main() { char *p, *s; if (!(p=alloc(SIZE))) /* allocate non-zeroed memory block */ abort(); if (!(s=malloc(SIZE))) /* allocate zeroed memory block */ abort(); if (memcmp(p,s,SIZE)) puts("Before zero(): memory compares different"); zero(p,SIZE); if (memcmp(p,s,SIZE)) puts("After zero(): memory compares different"); else puts("After zero(): memory compares same"); } Before zero(): memory compares different After zero(): memory compares same See also:`memccpy(), memchr(), memcpy(), memset() `Function Libraries` 4 - 119 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` memcpy(LIBC) memcpy(LIBC) This function will copy n characters from one area of memory to another. _____________________________________________________________ | | | `char *memcpy( s1, s2, n );` | | `char *s1, *s2; int n;` | | | | s1 - a pointer to the receiving memory area. | | | | s2 - a pointer to the originating memory area. | | | | n - the number of characters to copy. | |_____________________________________________________________| Description This function will perform a copy of "n" characters from the memory region pointed to by "s2" to the memory region pointed to by "s1". Warning There is no checking on the magnitude of "n"; thus, a memcpy() with an erroneous value for "n" could overwrite a critical portion of memory. Over- lapping copies may produce unpredictable results. Return Code The function returns a pointer to "s1". See also:`memccpy(), memchr(), memcmp(), memset() `Function Libraries` 4 - 120 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` memset(LIBC) memset(LIBC) This function sets a region of memory to a given character. _____________________________________________________________ | | | `char *memset( s, c, n );` | | `char *s; int c, n;` | | | | s - a pointer to the memory region to set. | | | | c - is the character value to set in memory. | | | | n - is the number of memory characters to set. | |_____________________________________________________________| Description This function will set "n" characters of memory starting with the address pointed to by "s" with the designated character, "c". Warning There is no checking on the magnitude of "n"; thus, a memset() with an erroneous value for "n" could overwrite a critical portion of memory. Return Code A pointer to "s" is returned. See also:`memccpy(), memchr(), memcmp(), memcpy() `Function Libraries` 4 - 121 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` modf(MATH) modf(MATH) This function obtains the signed fractional part of a double. _____________________________________________________________ | | | `#include ` | | `double modf( value, iptr );` | | `double value, *iptr;` | | | | value - the number to obtain the fractional part. | | | | iptr - a pointer to a double where the integer | | part of "value" is to be stored. | |_____________________________________________________________| Description This function returns the signed fractional part of the double, "value", and stores the integer part (as a double) in the location pointed to by "iptr". It is used to split a double floating point number into its integer part and its fractional part. Example #include stdio.h #include math.h char inbuf[81]; double d, f_part, int_part; main() { puts("modf: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; f_part = modf(d=atod(inbuf),&int_part); printf("d = %g; f = %g; i = %g\n",d,f_part,int_part); } } modf: enter your number: EOF to exit 1.234e2 |d = 123.4; f = 0.4; i = 123 -1765e-2 |d = -17.65; f = -0.65; i = -17 0.56789e4 |d = 5678.9; f = 0.9; i = 5678 See also:`frexp(), ldexp() `Function Libraries` 4 - 122 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` move(LIBC) move(LIBC) This function will copy a memory block in memory. _____________________________________________________________ | | | `void move( pfrom, pto, len );` | | `char *pfrom, pto; int len;` | | | | pfrom - the address of the block to be moved. | | | | pto - the address of the block's new starting | | address. | | | | len - the length of the block, in bytes. | |_____________________________________________________________| Description This function will perform a nondestructive move of a memory block. That means that if the "pto" address is less than the "pfrom" address, the move will start from the beginning of the block. If the "pto" address is greater than the "pfrom" address, the move will start from the end of the block. For portability across C compilers, it is recommended that you use the equivalent function, memcpy(). Warning There is no checking on the magnitude of "len"; thus, a move() with an erroneous value for "len" could overwrite a critical portion of memory. See also:`fill(), memccpy(), memchr(), memcmp(), memcpy(), memset(), zero() `Function Libraries` 4 - 123 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` open(LIBC) open(LIBC) This function is used to open a file for block I/O. _____________________________________________________________ | | | `#include ` | | `int open(path, oflag [,mode] );` | | `char *path; int oflag, mode;` | | | | path - a pointer to the string containing the | | file specification. | | | | oflag - is an ORing of bit-flags defined in fcntl.h | | which specify the access of the file. | | | | mode - user protection level when the O_CREAT flag | | is specified and the file does not exist. | |_____________________________________________________________| Description The open() function is used to prepare an existing file or newly created file for access via read(), write(), or lseek(), or other file operation. If the "oflag" argument specifies the O_CREAT flag, then open requires the third argument, "mode", which should contain the creation access mode to be applied to the designated file if it is non-existing [see creat()]. The "oflag" field is entered by ORing the desired conditions defined in the fcntl header file. These symbols are as follows: O_RDONLY /* Open for reading only */ O_WRONLY /* Open for writing only */ O_RDWR /* Open for reading and writing */ O_NDELAY /* Non-blocking I/O - unsupported */ O_APPEND /* Append (initial writes guaranteed at the end) */ O_CREAT /* Open with file create */ O_TRUNC /* Open with truncation */ O_EXCL /* Exclusive open - unsupported */ Exactly one of the first three must be specified. Return Code If an error is detected in opening the file, open() will return EOF (-1) and the global error variable, errno, will contain the UNIX error number which describes the error; otherwise, the file's descriptor will be returned. Warning If the "path" field references a character special device, you will not be able to use lseek() with the returned file descriptor. `Function Libraries` 4 - 124 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Example #include #include main(argc, argv) int argc; char *argv[]; { int fd1, fd2, n; char buf[BUFSIZE]; if (argc != 3) error("Usage: cp from to", NULL); if ((fd1=open(argv[1],O_RDONLY))==EOF) error("Can't open %s\n",argv[1]); if ((fd2=open(argv[2],O_WRONLY||O_CREAT,0777))==EOF) error("Can't create %s\n",argv[2]); while ((n = read(fd1, buf, 512)) > 0) if (write(fd2,buf,n)!=n) error("Write error\n",NULL); } error(s1, s2) char *s1, *s2; { printf(s1, s2); exit(1); } See also:`creat() `Function Libraries` 4 - 125 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` option(LIBC) option(LIBC) This function will set the state of and/or return the state of an option flag of MC. _____________________________________________________________ | | | `int option( flag, switch);` | | `int flag, switch;` | | | | switch - is the designated operation on flag; | | 0 to reset; 1 to set; 2 to test | | | | flag - is the designated flag to test or alter. | |_____________________________________________________________| Description This function can be used to alter any of the run-time option settings. The option masks are defined in the stdio header file and are as follows: O_ERRORMSG - When reset, the I/O system will be inhibited from displaying the usual DOS error message on an I/O error. This is the default. O_KBECHO - When set, and keyboard input will be echoed to stdout. The default is "reset". O_BRIEF - When set, this will force the I/O system to display brief error messages if O_ERRORMSG has also been set. MC defaults this to "reset". Return Code The function will return FALSE if the designated flag is reset, TRUE if the designated flag is set, or EOF if the designated flag is out of range. For "switch" equal to 0 or 1, the returned flag state is the state before the reset or set (i.e the state prior to the option() request). Example #include "stdio.h" main() { FILE *stream; option(O_ERRORMSG,1); if (!(stream=fopen("nosuchf.ile:7","r"))) perror("fopen error"); else fclose(stream); } ** Error code = 24, Returns to X'363F' ** File not in directory File = NOSUCHF/ILE:7 Last SVC = 102, Returned to X'1A19' fopen error: File not in directory `Function Libraries` 4 - 126 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` otoi(LIBC); otol(LIBC) otol(LIBC); otoi(LIBC) These functions are used to convert character strings of octal digits to their integer or long integer value. _____________________________________________________________ | | | `int otoi( string );` | | `char *string;` | | | | `long otol( string );` | | `char *string;` | | | | string - is a pointer to a string containing octal | | digits <0-7>. | |_____________________________________________________________| Description These standard C functions are used to convert strings containing octal character digits to their (long) integer equivalent. Conversion stops as soon as the first character not in the valid range is detected. The result is re- turned as the function value. Example #include stdio char inbuf[81]; int ival; main() { puts("Enter your octal number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; ival=otoi(inbuf); printf("Your number in decimal is: %d\n",ival); } } Enter your octal number: EOF to exit 1777 |Your number in decimal is: 1023 111 |Your number in decimal is: 73 1777777 |Your number in decimal is: -1 See also:`btoi(), btol(), xtoi(), xtol() `Function Libraries` 4 - 127 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` outport(IN) outport(IN) This function outputs a character to a machine port. _____________________________________________________________ | | | `#option INLIB` | | `void outport( port, value );` | | `int port, value; | | | | port - is the designated machine port. | | | | value - the low-order byte of value is output. | |_____________________________________________________________| Description The outport() function outputs the integer value to the port. The value is truncated to its low-order byte. Example`(partial illustration of dcal/ccc) #include stdio.h #define SELECT 0xf4 #define COMMAND 0xf0 #define STATUS COMMAND #define RESTORE 3 #define BUSY 1 #option INLIB int ds[4] = {1,2,4,8}; unsigned drive, ckpulse(); char buffer[81]; main() { input: { fputs("Enter floppy physical drive number <0-3> : ",stdout); if (!gets(buffer)) exit(0); drive = atoi(buffer); } if (drive > 3) goto input; printf("Insert a disk in floppy %d and depress return",drive); drive = ds[drive]; getchar(); outport(SELECT,drive); outport(COMMAND,RESTORE); while (inport(STATUS) & BUSY) { outport(SELECT,drive); if (inkey()) exit(0); } See also:`inport() `Function Libraries` 4 - 128 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` perror(LIBC) perror(LIBC) This function produces an error message on standard output. _____________________________________________________________ | | | `void perror( s );` | | `char *s;` | | | | s - is a pointer to a message string printed | | as a prefix to the generated message. | |_____________________________________________________________| Description The perror() function writes an error message corresponding to the error number contained in the global error variable, errno, to standard error out- put. The argument string, "s", is first written. Then a colon and blank are next written. Finally, a message describing the error number contained in "errno" is written followed by a new-line character. The "errno" message written by perror() is obtained from sys_errlist(). Note that in order to keep program-occupied memory to a minimum, sys_errlist is implemented in MC as a function which generates the message as required rather than as an array of message strings. Example #include stdio.h #option MAXFILES 5 char message[] = "Writing to dup'd file descriptor\n"; main() { int fildes; if ((fildes=dup2(STDOUT,10))==EOF) { perror("main: dup2() error"); exit(-1); } write(fildes,message,strlen(message)); } main: dup2() error: Illegal logical file number See also:`errno, sys_errlist() `Function Libraries` 4 - 129 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` pixel(IN) pixel(IN) This plotting function supports the block graphics mode available to the CRT screen to turn on, turn off, or determine the status of any point (pixel) in the screen image. _____________________________________________________________ | | | `#option INLIB` | | `int pixel( funcod, xval, yval);` | | `int funcod, x, y;` | | | | funcod - specifies whether the pixel is reset (0), | | set (1), or pointed (2). | | | | xval - specifies the horizontal coordinate. | | | | yval - specifies the vertical coordinate. | |_____________________________________________________________| Description The "pixel()" function can be used to point, reset, or set the pixel depending on the function code supplied as the argument. The function code (funcod) specifies the operation to be performed on the pixel. It is an integer value in the range <0-2>. These codes are used as follows: 0 - Indicates "reset", which will turn off (make dark) the pixel. 1 - Indicates "set", which will turn on (make light) the pixel. 2 - Indicates "point", which will return the status of the specified pixel. The status will be zero (0) for reset, one (1) for set, negative one (-1) if (x1,y1) is not in the CRT image, or negative two (-2) if the specified pixel does not contain a graphic character. The "xval" and "yval" are integers which specify the pixel position along the x-axis (horizontal) or y-axis (vertical). The value is a virtual pixel, which means that it does not have to be a position in the CRT image. The direction away from the origin is always considered to be in the positive direction (for more information on this subject, see the pmode() function). Return Code Pixel() returns a zero (0) to indicate that the pixel is reset; a one (1) to indicate that the pixel is set; a minus one (-1) to indicate that the point (x1,y1) is out of range (i.e. virtual and does not appear in the CRT image); a minus two (-2) to indicate that the pixel does not contain a gra- phics character; or a minus three (-3) to indicate that the function code passed to pixel() is invalid (not in the range <0-2>); otherwise, for func- tions 0 and 1, a NULL will be returned. See also:`box(), circle(), line(), point(), reset(), set() `Function Libraries` 4 - 130 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` point(IN) point(IN) This function is used to sense the state of a pixel in the screen image. _____________________________________________________________ | | | `#option INLIB` | | `int point ( xval, yval );` | | `int x, y;` | | | | xval - specifies the horizontal coordinate. | | | | yval - specifies the vertical coordinate. | |_____________________________________________________________| Description The "point()" function will obtain the state of the specified pixel according to the designated point, (x,y). The "xval" and "yval" values spec- ify the pixel position along the x-axis (horizontal) and y-axis (vertical) respectfively. The value is a virtual pixel, which means that it does not have to be a position in the CRT image. "point(xval,yval)" is equivalent to "pixel(2,xval,yval)". Return Code Point() returns a zero (0) to indicate that the pixel is reset; a one (1) to indicate that the pixel is set; a minus one (-1) to indicate that the point (x1,y1) is out of range (i.e. virtual and does not appear in the CRT image); and a minus two (-2) to indicate that the pixel does not contain a graphics character. See also:`box(), circle(), line(), pixel(), reset() set() `Function Libraries` 4 - 131 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ploc(IN) ploc(IN) This function establishes the starting address of the CRT image area. _____________________________________________________________ | | | `#option INLIB` | | `char *ploc( buffer );` | | `char *buffer;` | | | | buffer - specifies the starting address of the | | plotting image area. Plotting functions use | | the CRT address unless changed by ploc(). | |_____________________________________________________________| Description The ploc() function can be very powerful in creating dynamic displays. By establishing an off-CRT buffer equal in length to the CRT image area, its address can be passed via ploc() so that the plotting functions plot into the buffer. The buffer could be subsequently moved to the CRT image area with the move() function on memory-mapped video machines or via a SuperVisor Call request on banked video machines. On machines which do not have user-accessible memory-mapped video, an address of zero is used to reference the CRT. Ploc() is initialized to reference the video region. On machines with memory-mapped video, "address" is initialized to the video memory address. Thus, if you pass some other ad- dress via ploc(), you can restore plotting to the CRT by passing this CRT memory address via another ploc() invocation. An address of zero also will reference the video RAM; thus, denoting video reference via a ploc() argument of zero will be portable across all MC releases. Passing a zero as the address will also return the current ploc() ad- dress as the function value while it resets the referencing to the video. Warning The buffer must be large enough to contain the screen image. Example #option INLIB int r; unsigned regs[6]; char *p1; main() { putchar('\x0f'); if (!(p1=alloc(1920))) exit(-1); memset(p1,' ',1920); ploc(p1); for (r=1;r<40;r+=3) circle(1,79,35,r); regs[1]=0x500; regs[3]=p1; call(15,regs); getchar(); } See also:`pixel(), pmode() `Function Libraries` 4 - 132 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` pmode(IN) pmode(IN) The "pmode()" function establishes the CRT image area as one of the four quadrants in the cartesian coordinate system. _____________________________________________________________ | | | `#option INLIB` | | `int pmode( quadrant );` | | `int quadrant;` | | | | quadrant - sets the plotting image to quadrant <1-4> | | of the x-y plane; initialized to quadrant 4.| | If quadrant = 0, then the current quadrant | | number in effect will be returned. | |_____________________________________________________________| Description The pmode() function is quite useful when your application concerns the graphing of mathematical functions in the standard cartesian coordinate sys- tem. Since most functions are graphed in the first quadrant, a "pmode(1)" will establish the image area for that purpose. Please note that any graphics or characters currently on the screen at the time pmode() is invoked are left undisturbed; pmode() does NOT refresh the current screen contents to the re- vised quadrant but prepares the plotting functions for the new quadrant. "Quadrant" is used when changing the base origin of the plot image area with the pmode() function. The image area is considered to represent only one quadrant of the x-y plane in the cartesian coordinate system. The quadrants are numbered as follows: | 2 | 1 ________O|O_________ O|O 3 | 4 | with the point 0,0 (the origin) appearing at the corner identified with the letter "O". The standard quadrant used by the plotting functions will be quadrant 4 unless changed with a pmode() function call. Remember that the direction away from the origin is always considered to be positive. Return Code A return code of 1, 2, 3, or 4 indicates the current quadrant in effect when a pmode(0) function is invoked. A value of EOF (-1) is returned if "quadrant" is not in the range <0-4>. `Function Libraries` 4 - 133 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` pow(MATH) pow(MATH) This function raises a double value to a double power. _____________________________________________________________ | | | `#include "math.h"` | | `double pow( argx, argy );` | | `double argx, argy;` | | | | argx - is the base value to raise. | | | | argy - is the power to raise argx. | |_____________________________________________________________| Description This function will raise a double precision number to a double precision power and return a double precision result. Return Code Pow() returns 0 and sets errno to EDOM when argx is zero and argy is non-positive, or when argx is negative and argy is not an integer value. In both of these cases, a message is printed to standard error indicating DOMAIN error. When the correct value for the function would overflow or underflow the machine maximum or minimum for a double, pow() returns HUGE_VAL or zero respectively and sets errno to ERANGE. This error handling procedure may be changed via the matherr() function. Example #include stdio.h #include math.h double d,e,r; main() { option(O_KBECHO,1); puts("pow: Enter your x and y values: EOF to exit"); while (TRUE) { if (scanf("%lf %lf",&d,&e) != 2) break; errno=0; r = pow(d,e); printf("%g to the %g power = %g; errno = %d\n",d,e,r,errno); } } matherr(x) struct exception *x; { fprintf(stderr,"Type %d function error in %s...\n",x->type,x->name); fprintf(stderr," Args = %g,%g: ",x->arg1,x->arg2); return 0; } pow: Enter your x and y values: EOF to exit 2 32 | 2 to the 32 power = 4.29497e+09; errno = 0 -2 4 | -2 to the 4 power = 16; errno = 4 -5 4.7 | Type 1 function error in pow... | Args = -2,4.7: argument domain error | -2 to the 4.7 power = 0; errno = 70 See also:`exp(), log(), log10(), matherr(), sqrt() `Function Libraries` 4 - 134 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` printf(LIBC); printf(MATH) printf(MATH); printf(LIBC) These functions create a formatted image for standard output. _____________________________________________________________ | | | `#include "math.h"` ... optional | | `int printf( control, arg1, arg2, ...);` | | `char *control; args SEE TEXT` | | | | control - is a string containing transparent printing | | characters and conversion specifications. | | | | argn - arguments to be formatted for the output | | print image as specified by the control. | |_____________________________________________________________| Description The printf(...) function is used to write an output image to the stand- ard output device and is identical to fprintf(stdout,...). The specifications for formatting the output are determined by the character string, "control". This string will contain ordinary characters copied directly to the output image and/or specifications denoting the field conversions of all arguments. The conversion specifications are detailed under the documentation for fprintf(). Including the preprocessor statement, "#include math", will force an automatic search of the MATH/REL library during the link process and link the module which supports double precision floating point formatting. Return Code If an error is detected during printing, EOF will be returned; otherwise, the number of characters actually printed will be returned. Example printf("%d characters, %d lines were copied\n", bytes, lines); See also`fprintf(), sprintf(), scanf(), fscanf(), sscanf() `Function Libraries` 4 - 135 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` putc(LIBC); putchar(LIBC) putchar(LIBC); putc(LIBC) These functions are used to output a character to a file stream. _____________________________________________________________ | | | `int putc( c, stream);` | | `char c; FILE *stream;` | | | | `int putchar( c );` | | `char c;` | | | | c - is the character to be output. | | | | stream - is the file pointer for the output file. | |_____________________________________________________________| Description Putc() is used to output single characters to the file stream identified by the file pointer, "stream". 'c' is any of the 256 possible character codes. If an integer value is passed it is left-truncated, so that only the least significant byte is output. Putchar() outputs the character 'c' to the standard output file and is functionally equivalent to putc(c,stdout). Although some C implementations support putchar() as a #define macro, MC supports putchar() as a function. Return Code The return code is the character passed in 'c' if no errors are detected; otherwise, it will be different from the character passed in 'c'. When an error is detected, the global error variable, errno, will contain the UNIX error number which describes the error. Ferror() can also be used on the stream to obtain the DOS error number. Example if ( putc( c, fp ) != c ) return(1); else return(0); See also:`fputc(), puts(), putw() `Function Libraries` 4 - 136 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` puts(LIBC) puts(LIBC) This function is used to output a string to the standard output. _____________________________________________________________ | | | `int puts( string );` | | `char *string;` | | | | string - is the address of the string to be output. | |_____________________________________________________________| Description Puts() outputs "string" to the standard output file. All characters up to the first zero byte are output. A new-line character is then output. This function is similar to fputs(string,stdout); however, puts() adds a new-line character whereas fputs() does not. Return Code A NULL (zero) will be returned if no error was detected in the I/O operation, otherwise, the function will return EOF (-1) and the global error variable, errno, will contain the UNIX error number associated with the error. The DOS error may be recovered from the stream by invoking ferror(). Example if (argc!=3) { puts("Format error: compare file1 file2"); exit(); } See also:`putc(), putw() `Function Libraries` 4 - 137 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` putw(LIBC) putw(LIBC) This function will write a "word" to a stream output. _____________________________________________________________ | | | `int putw( word, stream );` | | `int word; FILE *stream;` | | | | word - is the integer value to write. | | | | stream - designates the output file stream. | |_____________________________________________________________| Description Putw() outputs a word to the designated stream. A "word" is the size of an integer. Return Code If an error is encountered during the output, the return code will be EOF (-1); otherwise, the word output will be returned. Warnings Since EOF is a valid integer value, ferror() or feof() must be used to differentiate between a -1 return and an error return. Note that since the low byte and high byte storage order of a word may vary in different machine environments, putw() is an environment dependent function. Example #include stdio.h main() { FILE *stream, fopen(); int ii, i, array[10]; if (!(stream=fopen("test.dat:7","w+"))) exit(-1); for ( i=0; i<10; i++) if (putw((ii=i*i),stream) != ii) fputs("fwrite error\n",stderr); rewind(stream); read(fileno(stream),array,sizeof(array)); for ( i=0; i<10; i++) printf("%d ",array[i]); fclose(stream); } 0 1 4 9 16 25 36 49 64 81 See also:`getc(), getw(), swab() `Function Libraries` 4 - 138 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` qsort(LIBC) qsort(LIBC) This function implements a recursive quicker sort algorithm. _____________________________________________________________ | | | `int qsort( base, nel, width, compar );` | | `char *base; unsigned int nel, width; int (*compar)();` | | | | base - a pointer to the base of the table to sort. | | | | nel - is the number of elements in the table. | | | | width - is the size of an element in bytes. | | | | compar - is a pointer to a comparison function which | | returns -1, 0, or +1 according to a | | comparison of two elements. | |_____________________________________________________________| Description This function implements Hoare's quicker sort algorithm. The implemen- tation orders the table via a recursive invocation of the ordering function. The comparison function must return a value less than zero, equal to zero, or greater than zero depending on whether a comparison of element_a to element_b finds element_a less than, equal to, or greater than element_b. Return Code If qsort() cannot obtain dynamic storage for the pivot element, an EOF is returned; otherwise, a NULL is returned to indicate success. Warning An attempt to qsort() a very large table may result in a stack overflow with unpredictable results. Example /* excerpt from sortsym/ccc */ if (read(0, (char *) base, fsize) != fsize) exit(1); /* read SYM file */ for ( i=0, record=base, recp=prec; i #include main(argc, argv) int argc; char *argv[]; { int fd1, fd2, n; char buf[BUFSIZE]; if (argc != 3) error("Usage: cp from to", NULL); if ((fd1=open(argv[1],O_RDONLY))==EOF) error("Can't open %s\n",argv[1]); if ((fd2=open(argv[2],O_WRONLY||O_CREAT,0777))==EOF) error("Can't create %s\n",argv[2]); while ((n = read(fd1, buf, 512)) > 0) if (write(fd2,buf,n)!=n) error("Write error\n",NULL); } error(s1, s2) char *s1, *s2; { printf(s1, s2); exit(1); } See also`close(), open(), write() `Function Libraries` 4 - 141 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` realloc(LIBC) realloc(LIBC) This function changes the length of a previously allocated block. _____________________________________________________________ | | | `char *realloc( ptr, size );` | | `char *ptr; unsigned int size;` | | | | ptr - is a pointer to the current block. | | | | size - is the size of the new block in bytes. | |_____________________________________________________________| Description This function may be used to increase or decrease the size of a block of memory previously allocated via malloc(), calloc(), alloc() or a previous realloc(). If the new block size is larger than the old block size, the existing contents of the block will be unaltered and the remainder of the block will be zeroed. If the new size is smaller than the old size, the contents of the block will be unaltered up to the new size. Return Code If no additional memory is available, realloc() returns a NULL pointer; otherwise, a pointer to the new block is returned. Warning If insufficient additional memory is available, the contents of the old block may be lost. Example mrealloc(ptr, newsize, oldsize) /* reallocate data space of size bytes */ char *ptr; unsigned newsize, oldsize; { static char *p; static int i; printf("attempting to reallocate %d bytes at %#X\n", newsize, ptr - 4); if (! (p = realloc(ptr, newsize))) /* couldn't do it */ return NULL; printf("reallocated %d bytes at %#X\n", newsize, p - 4); printf("data = "); for (i = 0; i < newsize; ++i) printf("%2.2X ", p[i]); printf("\n"); cfill(p, newsize - oldsize, oldsize); return p; } See also:`alloc(), brk(), calloc(), free(), malloc() `Function Libraries` 4 - 142 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` reset(IN) reset(IN) This function is used to turn off any point (pixel) in the screen image. _____________________________________________________________ | | | `#option INLIB` | | `int reset ( xval, yval );` | | `int x, y;` | | | | xval - specifies the horizontal coordinate. | | | | yval - specifies the vertical coordinate. | |_____________________________________________________________| Description The "reset()" function will turn off the specified pixel according to the designated point, (x,y). The "xval" and "yval" values specify the pixel position along the x-axis (horizontal) and y-axis (vertical) respectively. The value is a virtual pixel, which means that it does not have to be a position in the CRT image. "reset(x,y)" is identical in function to "pixel(0,x,y)". Return Code A return code of minus one (-1) indicates that the point (xval,yval) is out of range (i.e. virtual and does not appear in the CRT image). Example for ( x=0, y=40; x<128; x++) set( x, y ); for ( x=0, y=40; x<128; x++) reset( x, y ); See also:`box(), circle(), line(), pixel(), point() set() `Function Libraries` 4 - 143 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` rewind(LIBC) rewind(LIBC) This function positions a stream to its beginning. _____________________________________________________________ | | | `void rewind( stream );` | | `FILE *stream;` | | | | stream - is the stream file pointer. | |_____________________________________________________________| Description This function positions a stream to a zero offset relative to the beginning. The stream must be associated with a block file device rather than a character special device (i.e. isatty(fileno(stream)) must return FALSE). It is equivalent to "fseek(stream,0L,0);" except that no value is returned. Example #include stdio.h main() { FILE *stream, fopen(); int ii, i, array[10]; if (!(stream=fopen("test.dat:7","w+"))) exit(-1); for ( i=0; i<10; i++) if (putw((ii=i*i),stream) != ii) fputs("fwrite error\n",stderr); rewind(stream); read(fileno(stream),array,sizeof(array)); for ( i=0; i<10; i++) printf("%d ",array[i]); fclose(stream); } 0 1 4 9 16 25 36 49 64 81 See also:`fseek(), ftell() `Function Libraries` 4 - 144 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` rindex(LIBC) rindex(LIBC) This function obtains the position of the last occurrence of a specified character within a string. It is identical to strrchr(), its UNIX System V counterpart. _____________________________________________________________ | | | `char *rindex( s, c );` | | `char *s; int c;` | | | | s - is a pointer to the source string. | | | | c - is the character to find. | |_____________________________________________________________| Description The rindex() function will look for the last occurrence of character 'c' in the string pointed to by "s". The low-order byte of the integer, 'c', will be used as the character for which to look. Rindex() will operate properly when 'c' is the NULL character. Return Code If the character 'c' is not found in string "s", NULL will be returned; otherwise, a pointer to the position of the last 'c' in "s" will be returned. See also:`index(), strcat(), strcpy(), strcspn(), strncat(), strncpy(), strpbrk(), strchr(), strspn() `Function Libraries` 4 - 145 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` sbrk(LIBC) sbrk(LIBC) This function is used to obtain a memory block. _____________________________________________________________ | | | `char *sbrk( nbytes );` | | `unsigned int nbytes; | | | | `char *sbrk( 0 );` | | | | | | `nbytes ` - an unsigned integer number of bytes needed. | |_____________________________________________________________| Description Sbrk() reserves memory for use by a program from the system memory pool. The memory allocated by sbrk() cannot be deallocated until the program fin- ishes execution. Alloc() uses sbrk() to request blocks of memory as needed but maintains a linked list of blocks available but unallocated. If the mem- ory requested will only be needed for part of the execution of the program, it is recommended that either alloc(), calloc(), or malloc() be used. If the argument passed to sbrk() is zero, then the current value of the program break ($LOMEM) will be returned. This may be useful with brk(). Return Code The return code, "ptr", is the address of the allocated block of memory if the sbrk() was successful. If not enough memory is available to satisfy the request, "ptr" is set to NULL (0). Warnings Only memory allocated by sbrk(), alloc(), calloc(), malloc(), or realloc() should be used by the programmer for dynamic space. File opens and closes, including standard files, use these functions for setting up File Control Areas (FCA's). These FCAs can be clobbered if the program accesses unauthorized memory. If you inadvertantly pass a negative int as "nbytes", it will be treated as a large unsigned request. See also:`brk() `Function Libraries` 4 - 146 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` scanf(LIBC); scanf(MATH) scanf(MATH); scanf(LIBC) This function is used to scan a formatted print image from standard in- put, interpret the image fields according to a control string, and store the translated results in the arguments passed in the function's invocation. _____________________________________________________________ | | | `int scanf( control, arg1, arg2, ... );` | | `char *control; SEE TEXT for type of arg1, arg2, ... | | | | control - is the decoding control string. | | | | args - as required to match the control string. | |_____________________________________________________________| Description The scanf() function is the input analog of the printf() function. It provides similar translations; however, the conversions are from ASCII string fields to argument values. Scanf() inputs from standard input [stdin]. The arguments identified as "arg1, arg2, ..." MUST BE POINTERS, rather than values since the scan function stores the converted results into the arguments. For an argument defined as an array, its name will be a pointer. For all scaler arguments, use the "address of" operator. The control string is detailed under the documentation for fscanf(). The scanf() function contained in the LIBC library supports all variable types except floats and doubles; thus "e", "f", and "g" translations will be ignored unless #option MATHLIB is specified to request the MATH/REL scanf. Return Code If end-of-file is reached during the input, EOF will be returned. Otherwise, the function's return value will be equal to the number of suc- cessfully matched and assigned input items. Warnings Arguments receiving strings must be large enough to contain the string. Example #include #include main() { char achar, string[81], float f1; int n_items, aint; n_items = scanf("%c%3d%*2d%6s%f",&achar,&aint,string,&f1); printf("Count = %d |%c %d %s %e\n",n_items,achar,aint,string,(double)f1); } For input of: a12345abcdef 12.345e5 Prints : Count = 4 |a 123 abcdef 1.2345E+06 See also:`fscanf(), sscanf() `Function Libraries` 4 - 147 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` seek(LIBC) seek(LIBC) This function is used to randomly move around a file without actually reading or writing (unflushed output buffered by the system will be physi- cally written when a seek() is performed). _____________________________________________________________ | | | `int seek( fildes, offset, origin );` | | `int fildes, offset, origin; | | | | fildes - the file descriptor of the file. | | | | offset - the new position relative to origin. | | | | origin - specifies offset from beginning, current, | | or end for origin equal to 0, 1, or 2. | | For origin values of 3, 4, or 5, offset is | | multiplied by 512 prior to the seek and | | origin is then reinterpreted as 0, 1, or 2. | |_____________________________________________________________| Description The seek() function is used for random positioning in a file. Since offset is treated as a signed integer, you can only seek within 32K of a position (beginning, current, or end). For files of size greater than 64K, it is best to consistently use a 512-byte block seek followed by a block offset seek to postion to a location. Thus for large files, you can use origins of 3, 4, or 5 to seek to any given 512-byte block then invoke a subsequent seek to position to the offset from that block. It is recommended that you use the long form of the function, lseek(). Return Code On origins of 0, 1, or 2, the positive offset from the current 512-byte block prior to the seek will be returned. On origins of 3, 4, or 5, the num- ber of the current 512-byte block will be returned. These numbers may be used to calculate the current record position or the number of records in a file. If an error occurs during the seek, EOF (-1) will be returned. Warning The file descriptor passed as the fildes argument of the function must be one obtained from open(), creat(), dup(), dup2(), or fcntl(), or be a standard file descriptor: STDIN, STDOUT, STDERR. Also, remember that the offset is treated as a SIGNED integer. Thus, a negative offset passed with an origin of 0 or 3 is an error. You can't seek a tty device! See also:`isatty(), lseek(), fseek() `Function Libraries` 4 - 148 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` set(IN) set(IN) This function is used to turn on any point (pixel) in the screen image. _____________________________________________________________ | | | `#option INLIB` | | `int set ( xval, yval );` | | `int x, y;` | | | | xval - specifies the horizontal coordinate. | | | | yval - specifies the vertical coordinate. | |_____________________________________________________________| Description The "set()" function will turn on the specified pixel according to the designated point, (x,y). The "xval" and "yval" values specify the pixel position along the x-axis (horizontal) and y-axis (vertical) respectively. The value is a virtual pixel, which means that it does not have to be a position in the CRT image. "set(x,y)" is identical in function to "pixel(1,x,y)". Return Code A return code of minus one (-1) indicates that the point (xval,yval) is out of range (i.e. virtual and does not appear in the CRT image). Example for ( x=0, y=40; x<128; x++) set( x, y ); for ( x=0, y=40; x<128; x++) reset( x, y ); See also:`box(), circle(), line(), pixel(), point() reset() `Function Libraries` 4 - 149 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` setjmp(LIBC) setjmp(LIBC) This function saves the environment for a "far" return via longjmp(). _____________________________________________________________ | | | `#include ` | | `int setjmp( env );` | | `jmp_buf env; | | | | env - is the environment saved by setjmp(). | | | | val - is the value returned by setjmp(). | |_____________________________________________________________| Description The initial call to setjmp() always returns zero. A subsequent longjmp() using the same environment will restore the program to the environment as saved in "env" by the previous call to setjmp(). After the longjmp() is completed, the program execution will continue as if the corresponding call to setjmp() had just occurred; however, the returned value will be the value passed as "val" in the longjmp() call, rather than zero. The setjmp()/longjmp() companion functions can be used in error control within nested functions so as to effect an escape from a lower-level function error without backtracking through error handling in each higher level nest. Warning The values of automatic and register variables are unpredictable following a longjmp(). Do not use setjmp() in any expression other than an immediate assignment or relational test. Example #include setjmp.h jmp_buf env; main() { int i, val; if (val=setjmp(env)) printf("Error %d on i=%d\n",val,i); else for (i=0;i<3;++i) { func1(i); printf("No error %d\n",i); } } func1(i) int i; { func2(i); } func2(i) int i; { func3(i); } func3(i) int i; { if (i<2) return; else longjmp(env,1); } See also:`longjmp() `Function Libraries` 4 - 150 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` sin(MATH) sin(MATH) This function obtains the trigonometric sine of a double. _____________________________________________________________ | | | `#include ` | | `double sin( value );` | | `double value;` | | | | value - the double whose sine is desired. | |_____________________________________________________________| Description The sin() function obtains the triginometric sine of the double argument entered in radians. The result is a double. Example #include stdio.h #include math.h char inbuf[81]; double d1,d2; main() { puts("sin: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; d2 = sin(d1=atod(inbuf)); printf("sin of %g = %1.14f; errno = %d\n",d1,d2,errno); } } sin: enter your number: EOF to exit 1.5707963 | sin of 1.5708 = 1.00000000000000; errno = 0 1 | sin of 1 = 0.84147098480790; errno = 0 -1 | sin of -1 = -0.84147098480790; errno = 0 See also:`asin(), cos(), tan(), fsin() `Function Libraries` 4 - 151 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` sinh(MATH) sinh(MATH) This function obtains the hyperbolic sine of a double. _____________________________________________________________ | | | `#include ` | | `double sinh( value );` | | `double value;` | | | | value - a double whose hyperbolic sine is desired. | |_____________________________________________________________| Description The sinh() function obtains the hyperbolic sine of the double argument entered in radians. The result is a double. Example #include stdio.h #include math.h char inbuf[81]; double d1,d2; main() { puts("sinh: enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; d2 = sinh(d1=atod(inbuf)); printf("sin of %g = %1.14f; errno = %d\n",d1,d2,errno); } } sinh: enter your number: EOF to exit .5 | sin of 0.5 = 0.52109530549375; errno = 0 1.0 | sin of 1 = 1.17520119364380; errno = 0 10.0| sin of 10 = 11013.23287470339369; errno = 0 See also:`cosh(), tanh() `Function Libraries` 4 - 152 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` sprintf(LIBC); sprintf(MATH) sprintf(MATH); sprintf(LIBC) These functions create a formatted image for output to a string. _____________________________________________________________ | | | `int sprintf( buffer, control, arg1, arg2, ... );` | | `char *buffer, *control; args SEE TEXT` | | | | buffer - the string area to receive the output. | | | | control - is a string containing transparent printing | | characters and conversion specifications. | | | | argn - arguments to be formatted for the output | | print image as specified by the control. | |_____________________________________________________________| Description The sprintf() function performs the same formatted output operations as the printf() and fprintf() functions; however, the output is placed in a string buffer and is terminated by a NULL ['\0']. The specifications for formatting the output are determined by the character string, "control". This string will contain ordinary characters copied directly to the output image and/or specifications denoting the field conversions of all arguments. The conversion specifications take the form of: %{flags}{width}{.prec}char and are detailed under the documentation for fprintf(). Sprintf() may be used when more flexible control over floating point formatting is required than that provided by dtoa() and ftoa(). Warning The buffer must be large enough to contain the entire formatted string. Return Code The number of actual characters printed excluding the terminating NULL is returned. Example sprintf(buf,"%d characters, %d lines were copied",bytes,lines); puts( buffer ); See also:`dtoa(), fprintf(), fscanf(), ftoa(), printf(), scanf(), sscanf() `Function Libraries` 4 - 153 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` sqrt(MATH) sqrt(MATH) This function obtains the square root of a double. _____________________________________________________________ | | | `#include ` | | `double sqrt( value );` | | `double value;` | | | | value - a double whose square root is desired. | |_____________________________________________________________| Description The sqrt() function obtains the double precision square root of its double precision argument. The result is a double. Return Code Sqrt() returns 0 and sets the global error variable, errno, to EDOM when "value" is negative. A message indicating DOMAIN error will also be written to standard error. These procedures may be changed via matherr(). Example #include stdio.h #include math.h int i; char inbuf[81]; double d1,d2; main() { puts("sqrt: Enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; errno=0; d2 = sqrt(d1=atod(inbuf)); printf("The square root of %g is %g; errno = %d\n",d1,d2,errno); } } matherr(x) struct exception *x; { fprintf(stderr,"Type %d function error in %s...\n",x->type,x->name); fprintf(stderr," Args = %g,%g: ",x->arg1,x->arg2); return 0; } sqrt: Enter your number: EOF to exit 170e6 | The square root of 1.7e+08 is 13038.4; errno = 0 -9 | Type 1 function error in sqrt... | Args = -9,0: Argument domain error | The square root of -9 is 3; errno = 70 See also:`exp(), log(), pow() `Function Libraries` 4 - 154 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` srand(LIBC) srand(LIBC) This function seeds the pseudo-random number generator, rand(). _____________________________________________________________ | | | `void srand( seed );` | | `unsigned int seed;` | | | | seed - a seed for the rand() number generator. | |_____________________________________________________________| Description The srand() function may be invoked anytime to seed the random number generator, rand(). Rand() is initially seeded to a value of 1 by the system. Example main() { int loop; for (loop=0; loop < 12; loop++) printf("%d ",rand()); putchar('\n'); srand(1); for (loop=0; loop < 12; loop++) printf("%d ",rand()); } 16838 5758 10113 17515 31051 5627 23010 7419 16212 4086 2749 12767 16838 5758 10113 17515 31051 5627 23010 7419 16212 4086 2749 12767 See also:`frnd(), fseed(), rand() `Function Libraries` 4 - 155 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` sscanf(LIBC); sscanf(MATH) sscanf(MATH); sscanf(LIBC) These functions are used to scan a formatted print image stored in a string, interpret the image fields according to a control string, and store the translated results in the arguments passed in the function's invocation. _____________________________________________________________ | | | `int sscanf( buffer, control, arg1, arg2, ... );` | | `char *buffer, *control; args SEE TEXT` | | | | buffer - the string area containing the input image. | | | | control - a string containing translation control. | | | | args - as required to match the control string. | |_____________________________________________________________| Description The sscanf() function is the input analog of the sprintf() function. It provides similar translations; however, the conversions are from ASCII string fields to argument values. The arguments identified as "arg1, arg2, ..." MUST BE POINTERS, rather than values since the scan functions store the converted results into the arguments. The format of the control string is detailed under the documenta- tion for scanf(). If the end of the string is reached during the input, a newline char- acter will be automatically supplied to serve as a terminating whitespace. A typical use for sscanf() is to provide reformatting of variables under controlled conditions using internal memory buffers along with the comple- mentary function, sprintf(). Return Code When the end of the string is reached during the input, sscanf first treats it as a new-line character for the purpose of terminating the scanned field by whitespace. Subsequent requests for "input" from the string will return EOF. Otherwise, the function's return value will be equal to the num- ber of successfully matched and assigned input items. See also:`fscanf(), scanf(), sprintf() `Function Libraries` 4 - 156 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strcat(LIBC) strcat(LIBC) This function appends one string to another. _____________________________________________________________ | | | `char *strcat( dest, source );` | | `char *dest, *source;` | | | | dest - is a pointer to the destination string. | | | | source - is a pointer to the source string. | |_____________________________________________________________| Description The strcat() function will concatenate (append) the source string to the destination string. The "dest" argument is a pointer to a character array which must be of sufficient size to contain the appended string. Return Code A pointer to the "dest" string is returned. Example char string[81], lilbuf[9]; main() { strcpy(string,"Today is "); strcat(string,sysdate(lilbuf)); strcat(string," and the time is "); strcat(string,systime(lilbuf)); puts(string); } Today is 11/21/85 and the time is 14:50:56 See also:`strchr(), strcpy(), strcspn(), strncat(), strncpy(), strpbrk(), strrchr(), strspn() `Function Libraries` 4 - 157 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strchr(LIBC) strchr(LIBC) This function finds the first occurrence of a character in a string. _____________________________________________________________ | | | `char *strchr( s, c );` | | `char *s; int c;` | | | | s - is a pointer to the source string. | | | | c - is the character to find. | |_____________________________________________________________| Description The strchr() function will look for the first occurrence of character 'c' in the string pointed to by "s". The low-order byte of the integer, 'c', will be used as the character. Strchr() will operate correctly when 'c' is the NULL character. Return Code If the character 'c' is not found in string "s", NULL will be returned; otherwise, a pointer to the position of 'c' in "s" will be returned. Example char *p, string[81]; main() { puts("Enter your string; EOF to exit"); for (;;) { if (!gets(string)) break; p=string; /* point p to string[0] */ while (p=strchr(p,'.')) /* until no more dots */ *p='?'; /* replace '.' with '?' */ puts(string); } } Enter your string; EOF to exit this is a test. | this is a test? This "..." is an elipsis of dots. | This "???" is an elipsis of dots? See also:`strcat(), strcpy(), strcspn(), strncat(), strncpy(), strpbrk(), strrchr(), strspn() `Function Libraries` 4 - 158 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strcmp(LIBC) strcmp(LIBC) _____________________________________________________________ | | | `int strcmp( string_1, string_2 );` | | `char *string_1, *string_2;` | | | | string_1 - is a pointer to the first string. | | | | string_2 - is a pointer to the second string. | |_____________________________________________________________| Description This function compares "string_1" to "string_2" and returns an integer less than zero, equal to zero, or greater than zero, depending on whether "string_1" is lexicographically less than, equal to, or greater than "string_2". Return Code The return code of strcmp() is <0, 0, or >0 as noted above. Example If you are unfamiliar with how ASCII strings are "ordered", perhaps a strong example will clarify this discussion. The following is an ordered list of strings in ascending order: a8bcde abc abcd jim karl rich roy this_is_a_long_string Keep this ordered list in mind in the following examples. The statement: if (strcmp("abc","a8bcd") < 0) ? printf("above") : printf("below"); should print the word, "below" since the string, "abc" is below the string "a8bcd" in an ascendingly sorted list. The statement: if (strcmp("abc","abcd") < 0) ? printf("above") : printf("below"); should print the word, "above" since the string, "abc" is above the string "abcd" in an ascendingly sorted list. See also:`strcat(), strchr(), strcpy(), strcspn(), strncat(), strncpy(), strpbrk(), strrchr(), strspn() `Function Libraries` 4 - 159 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strcpy(LIBC) strcpy(LIBC) This function copies one string into another. _____________________________________________________________ | | | `char *strcpy( dest, source );` | | `char *dest, *source;` | | | | dest - is a pointer to the destination string. | | | | source - is a pointer to the source string. | |_____________________________________________________________| Description The strcpy() function copies an image of the source string to the des- tination string buffer. Strcpy() is useful to initialize an allocated but unzeroed character array to known string value. You cannot use strcat() to copy a string into a buffer unless either the first element of the buffer is known to be NULL or the buffer contains a string; thus, strcpy() is useful in order to "prime" a string buffer. Warning The destination character array must be large enough to contain the source string. Return Code A pointer to the "dest" string is returned. Example char string[81], lilbuf[9]; main() { strcpy(string,"Today is "); /* initialize output string */ strcat(string,sysdate(lilbuf)); /* add date to string */ strcat(string," and the time is "); strcat(string,systime(lilbuf)); /* add time to string */ puts(string); } Today is 11/21/85 and the time is 14:50:56 See also:`strcat(), strchr(), strcspn(), strncat(), strncpy(), strpbrk(), strrchr(), strspn() `Function Libraries` 4 - 160 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strcspn(LIBC) strcspn(LIBC) This function obtains the length of the initial substring of a first string composed entirely of characters not found in a second string. _____________________________________________________________ | | | `int strcspn( string_1, string_2 );` | | `char *string_1, string_2;` | | | | string_1 - is a pointer to the first string. | | | | string_2 - is a pointer to the second string. | |_____________________________________________________________| Description This function will scan "string_1" for a substring of characters begin- ning with the first character of "string_1" which is composed entirely of characters not found in "string_2". Both the "string_1" and "string_2" argu- ments should be pointers to character arrays. Return Code The length of the resulting substring is returned. Example char string[81], *field = "aeiou"; main() { int count; puts("Enter your string; EOF to exit"); for (;;) { if (!gets(string)) break; if (count=strcspn(string,field)) { *(string+count)='\0'; printf("Substring <%s> contains no vowels\n",string); } else puts("A vowel starts your entry"); } } Enter your string; EOF to exit "rhythm" is a great word for the game of hangman! Substring <"rhythm" > contains no vowels See also:`strcat(), strchr(), strcpy(), strncat(), strncpy(), strpbrk(), strrchr(), strspn() `Function Libraries` 4 - 161 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strepl(IN) strepl(IN) This function replaces a substring of one string with another string. _____________________________________________________________ | | | `char *strepl( source, dest, pos, count );` | | `char *source, *dest; int pos, count;` | | | | count - is the destination sub-string length. | | | | dest - is a pointer to the destination string. | | | | pos - starting index position or array subscript. | | | | source - is a pointer to the source string. | |_____________________________________________________________| Description The strepl() function replaces that portion of the destination string starting at relative position "pos" and continuing for "count" characters [the destination substring] with the source string. The argument "pos" represents a starting position relative to the beginning of the destination string. It is essentially used as an index or subscript into the "dest" character array. The argument, "count", controls how much of the destination string is to be replaced. If "count" is zero (0), then an insert operation is performed without deleting any characters of the destination string. The length of the replacement string is the length of the entire source string. If the source string is null (i.e. of zero length), then only the identified destination sub-string is deleted. Warning The destination character array must be of a size sufficient to contain the generated string. Return Code If "dest+pos" exceeds the bounds of the destination string, a NULL (0) will be returned and the string operation will be aborted; otherwise, a pointer to the destination string will be returned. For instance: if (!strepl(s, "destination_string", 24, 3)) puts("String error!"); will result in the error message display since the position, 24, is not in the range of the destination string. See also:`strcat(), strchr(), strcpy(), strcspn(), strncat(), strncpy(), strpbrk(), strrchr(), strspn() `Function Libraries` 4 - 162 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strept(IN) strept(IN) This function replicates a string. _____________________________________________________________ | | | `#option INLIB` | | `char *strept( dest, source, repeat );` | | `char *dest, *source; int repeat;` | | | | dest - is a pointer to the destination string. | | | | source - is a pointer to the source string. | | | | repeat - a repetition counter. | |_____________________________________________________________| Description The strept() function replicates the source string into the destination string the number of times indicated by "repeat". Both "source" and "dest" represent pointers to character arrays. Note that the replication uses the entire source string and not just the first source string character. Return Code The function returns a pointer to the destination string. Warning The destination character array must be of a size sufficient to hold the resultant string generation. Example #option INLIB char string[81], *repeats[5] = {"*","*=.","*_* ","{[(<>)]}","=="}; main() { int loop; for (loop=0; loop<5; loop++) puts(strept(string,repeats[loop],5)); } ***** *=.*=.*=.*=.*=. *_* *_* *_* *_* *_* {[(<>)]}{[(<>)]}{[(<>)]}{[(<>)]}{[(<>)]} ========== See also:`strepl(), stright(), strleft(), strmid(), strfind() `Function Libraries` 4 - 163 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strfind(IN) strfind(IN) This function will obtain the position of a substring in a string. _____________________________________________________________ | | | `#option INLIB` | | `char *strfind( dest, source, pos );` | | `char *dest, *source; int pos;` | | | | dest - is a pointer to the destination string. | | | | pos - starting index position or array subscript. | | | | source - is a pointer to the source string. | |_____________________________________________________________| Description The strfind() function will search the destination string for the first appearance of the source string. The destination string will be searched starting at the position "dest+pos". Both "source" and "dest" represent pointers to character arrays containing the respective strings. "Pos" is the starting position relative to the beginning of the destination string. Return Code If the source string is a null string, the value of "dest+pos" will be returned. If the destination string is a null string or if the source string is not found (i.e. is not a sub-string of the destination), a NULL (0) will be returned. If the source string is found in the destination string, a pointer to its position in the destination string will be returned. Example #option INLIB char *p, *string = "This is string one"; char *find[5] = {"hello","is","is","is","is"}; int loop, pos[5] = { 0,0,3,8,20 }; main() { for (loop = 0; loop < 5; loop++) if(p=strfind(string,find[loop],pos[loop])) printf("Found %s[%d]: %s\n",find[loop],pos[loop],p); else printf("Could not find %s[%d]\n",find[loop],pos[loop]); } Could not find hello[0] Found is[0]: is is string one Found is[3]: is string one Could not find is[8] Could not find is[20] See also:`strepl(), strept(), strleft(), strmid(), strfind() `Function Libraries` 4 - 164 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` stright(IN) stright(IN) This function obtains the rightmost substring of a string. _____________________________________________________________ | | | `#option INLIB` | | `char *stright( dest, source, count );` | | `char *dest, *source; int count;` | | | | count - is the integer sub-string length. | | | | dest - is a pointer to the destination string. | | | | source - is a pointer to the source string. | |_____________________________________________________________| Description The stright() function will copy the rightmost "count" characters (the sub-string) of the source string to the destination string. This is NOT an append operation. The destination string is replaced with the sub-string. "Count" indicates the length of desired substring. If "count" is zero, the destination becomes a null string. If the "count" is greater than the source string length, the entire source string is copied. Warning The destination character array should be dimensioned large enough to contain the entire sub-string and terminating NULL. Return Code The function returns a pointer to the resulting string. Example #option INLIB char *string = "This is a test string", buf[100]; main() { int loop; for (loop=5; loop<30; loop+=5) puts(stright(buf,string,loop)); } tring est string s a test string his is a test string This is a test string See also:`strepl(), strept(), strleft(), strmid(), strfind() `Function Libraries` 4 - 165 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strleft(IN) strleft(IN) This function obtains the leftmost substring of a string. _____________________________________________________________ | | | `#option INLIB` | | `char *strleft( dest, source, count );` | | `char *dest, *source; int count;` | | | | count - is the integer sub-string length. | | | | dest - is a pointer to the destination string. | | | | source - is a pointer to the source string. | |_____________________________________________________________| Description The strleft() function will copy the leftmost "count" characters (the sub-string) of the source string to the destination string. This is NOT an append operation. The destination string is replaced with the sub-string. "Count" indicates the length of the desired substring. If "count" is zero, the destination becomes a null string. If the "count" is greater than the source string length, the entire source string is copied. Warning The destination character array should be large enough to contain the entire substring and terminating NULL. Return Code The function returns a pointer to the resulting string. Example #option INLIB char *string = "This is a test string", buf[100]; main() { int loop; for (loop=5; loop<30; loop+=5) puts(strleft(buf,string,loop)); } This This is a This is a test This is a test strin This is a test string See also:`strepl(), strept(), stright(), strmid(), strfind() `Function Libraries` 4 - 166 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strlen(LIBC) strlen(LIBC) This function obtains the length of a string. _____________________________________________________________ | | | `int strlen( source );` | | `char *source;` | | | | source - is a pointer to the source string. | |_____________________________________________________________| Description The strlen() function returns the length of the source string. The length of a string is the number of characters up to but not including the first NULL. Return Code The return code of strlen() is the length of the target string. Example #include stdio.h char buffer[81]; main() { puts("strlen: Enter your string; EOF to exit"); while (TRUE) { if (!gets(buffer)) break; printf("Your string length is %d\n",strlen(buffer)); } } strlen: Enter your string; EOF to exit this is a test string |Your string length is 21 when in the course of human events |Your string length is 34 she sells sea shells down by the seashore|Your string length is 41 to err is human; to forgive is divine |Your string length is 37 See also:`strcat(), strchr(), strcpy(), strcspn(), strncat(), strncpy(), strpbrk(), strrchr(), strspn() `Function Libraries` 4 - 167 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strmid(IN) strmid(IN) This function will obtain a substring from a string. _____________________________________________________________ | | | `#option INLIB` | | `char *strmid( dest, source, pos, count);` | | `char *dest, *source; int pos, count;` | | | | count - is the integer sub-string length. | | | | dest - is a pointer to the destination string. | | | | pos - starting index position or array subscript. | | | | source - is a pointer to the source string. | |_____________________________________________________________| Description Strmid() replaces the destination string with a substring of "count" characters starting at the source string position, "source+pos". "Pos" is the starting position relative to the beginning of the source string. Both "dest" and "source" represent pointers to character arrays. "Count" indicates the length of the desired substring. If "count" is zero, the destination string will be null. "Count" may be greater than the length of "source+pos". Warning The destination array must be a size sufficient to hold the sub-string. Return Code If "source+pos" exceeds the bounds of the source string, a NULL (0) will be returned and no string replacement will occur; otherwise, strmid() will return a pointer to the destination string. For instance: if ( !strmid(s,"error",6,3) ) puts("String error!"); will result in the error message display since the position, 6, is not in the range of the string, "error". Example #option INLIB char *string = "This is a very long test string", buf[100]; main() { int loop; for (loop=0; loop<30; loop+=5) puts(strmid(buf,string,loop,11)); } This is a v | is a very l | very long t | long test s | test string | string See also:`strepl(), strept(), stright(), strleft(), strfind() `Function Libraries` 4 - 168 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strncat(LIBC) strncat(LIBC) This function appends at most "n" characters of one string to another. _____________________________________________________________ | | | `char *strncat( dest, source, n );` | | `char *dest, *source; int n;` | | | | dest - is a pointer to the destination string. | | | | source - is a pointer to the source string. | | | | n - the maximum number of characters to append | |_____________________________________________________________| Description The strncat() function will concatenate (append) at most "n" characters of the source string to the destination string. If "n" is greater than strlen(source) then the entire source string will be appended. Warning The "dest" character array must be large enough to contain the resulting string. Return Code A pointer to the "dest" string is returned. Example char *init = "Now is the time for all good men ", *string = "to come to the aid of their country", buf[100]; main() { int loop; for (loop=10; loop<40; loop+=5) { strcpy(buf,init); /* init buf */ puts(strncat(buf,string,loop)); } } Now is the time for all good men to come to Now is the time for all good men to come to the Now is the time for all good men to come to the aid o Now is the time for all good men to come to the aid of the Now is the time for all good men to come to the aid of their co Now is the time for all good men to come to the aid of their country See also:`strchr(), strcpy(), strcspn(), strncat(), strncpy(), strpbrk(), strrchr(), strspn() `Function Libraries` 4 - 169 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strncmp(LIBC) strncmp(LIBC) This function compares at most "n" characters of one string to another. _____________________________________________________________ | | | `int strncmp( string_1, string_2, n );` | | `char *string_1, *string_2; int n; | | | | string_1 - is a pointer to the first string. | | | | string_2 - is a pointer to the second string. | | | | n - the maximum number of characters to compare.| |_____________________________________________________________| Description This function will compare at most "n" characters of "string_1" to "string_2" and return and integer less than zero, equal to zero, or greater than zero, depending on whether "string_1" is lexicographically less than, equal to, or greater than "string_2". Return Code The return code of strcmp() is <0, 0, or >0 as noted above. Example If you are unfamiliar with how ASCII strings are "ordered", perhaps a strong example will clarify this discussion. The following is an ordered list of strings in ascending order: a8bcde abc abcd rich roy this_is_a_long_string Keep this ordered list in mind in the following examples. The statement: if (strncmp("abc","a8bcd",2)<0) ? printf("above") : printf("below"); should print the word, "below" since the string, "ab" is below the string "a8" in an ascendingly sorted list. The statement: if (strncmp("abc","abcd",4)<0) ? printf("above") : printf("below"); should print the word, "above" since the string, "abc" is above the string "abcd" in an ascendingly sorted list. See also:`strcat(), strchr(), strcmp(), strcpy(), strcspn(), strncat(), strncpy(), strpbrk(), strrchr(), strspn() `Function Libraries` 4 - 170 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strncpy(LIBC) strncpy(LIBC) This function copies at most "n" characters of one string into another. _____________________________________________________________ | | | `char *strncpy( dest, source, n );` | | `char *dest, *source; int n;` | | | | dest - is a pointer to the destination string. | | | | source - is a pointer to the source string. | | | | n - the maximum number of characters to copy. | |_____________________________________________________________| Description The strncpy() function copies an image of at most "n" characters of the source string to the destination string buffer. If the length of "source" is equal to or greater than "n",`the result will NOT be null-terminated.`If the length of "source is less than "n", NULLs will be added to "dest". Return Code A pointer to the "dest" string is returned. Example char *string = "123456789012345678901234567890", buf[100]; main() { int loop; for (loop=25; loop; loop-=5) { strncpy(buf,string,loop); /* copy ast most n chars */ *(buf+loop)='\0'; /* add NULL, in case! */ puts(buf); /* display the result */ } } 1234567890123456789012345 12345678901234567890 123456789012345 1234567890 12345 See also:`strcat(), strchr(), strcpy(), strcspn(), strncat(), strpbrk(), strrchr(), strspn() `Function Libraries` 4 - 171 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strpbrk(LIBC) strpbrk(LIBC) This function finds the first occurrence in one string of any character in another. _____________________________________________________________ | | | `char *strpbrk( string_1, string_2 );` | | `char *string_1, *string_2;` | | | | string_1 - is a pointer to the first string. | | | | string_2 - is a pointer to the second string. | |_____________________________________________________________| Description This function will scan through "string_1" and return a pointer to the first character in "string_1" which is also found in "string_2". Return Code A NULL will be returned if no character of "string_1" is contained in "string_2"; otherwise, a pointer to the matching character in "string_1" is returned. Example #option INLIB char *init = "the quick brown fox jumped over the lazy dogs back", *find[4] = {"aeiou","abc","xyz",",.;:?"}, *p; main() { int loop; puts(init); for (loop=0; loop<4; loop++) { if (p=strpbrk(init,find[loop])) printf("Found char in set [%s] at init+%d\n",find[loop],p-init); else printf("No chars from set [%s] in init\n",find[loop]); } } the quick brown fox jumped over the lazy dogs back Found char in set [aeiou] at init+2 Found char in set [abc] at init+7 Found char in set [xyz] at init+18 No chars from set [,.;:?] in init See also:`strcat(), strchr(), strcmp(), strcpy(), strcspn(), strncat(), strncpy(), strrchr(), strspn() `Function Libraries` 4 - 172 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strrchr(LIBC) strrchr(LIBC) This function finds the last occurrence of a character in a string. _____________________________________________________________ | | | `char *strrchr( s, c );` | | `char *s; int c;` | | | | s - is a pointer to the source string. | | | | c - is the character to find. | |_____________________________________________________________| Description The strrchr() function will look for the last occurrence of character 'c' in the string pointed to by "s". The low-order byte of the integer, 'c', will be used as the character for which to look. Strrchr() will operate properly when 'c' is the NULL character. Return Code If the character 'c' is not found in string "s", NULL will be returned; otherwise, a pointer to the position of the last 'c' in "s" will be returned. Example int find[4] = {'a','e','i','o'}; char *p, *rule = "012345678901234567890123456789012345678901234567890123456789012345", *init = "this function finds the last occurrence of a character in a string"; main() { int loop; puts(rule); puts(init); for (loop=0; loop<4; loop++) { if (p=strrchr(init,find[loop])) printf("Found last char %c at init+%d\n",find[loop],p-init); else printf("Char %c not in init\n",find[loop]); } } 012345678901234567890123456789012345678901234567890123456789012345 this function finds the last occurrence of a character in a string Found last char a at init+58 Found last char e at init+52 Found last char i at init+63 Found last char o at init+40 See also:`strcat(), strcpy(), strcspn(), strncat(), strncpy(), strpbrk(), strchr(), strspn() `Function Libraries` 4 - 173 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` strspn(LIBC) strspn(LIBC) This function obtains the length of the initial substring of a first string composed entirely of characters found in a second string. _____________________________________________________________ | | | `int strspn( string_1, string_2 );` | | `char *string_1, string_2;` | | | | string_1 - is a pointer to the first string. | | | | string_2 - is a pointer to the second string. | |_____________________________________________________________| Description The "strspn" function will scan "string_1" for a substring of characters beginning with the first character of "string_1" which is composed entirely of characters found in "string_2". The "string_1" and "string_2" arguments represent pointers to character arrays which contain the strings. Return Code The length of the resulting substring is returned. Example char string[81], substr[81], *field = "asdfghjkl"; main() { int count; puts("Enter your string; EOF to exit"); for (;;) { if (!gets(string)) break; if (count=strspn(string,field)) { *(string+count)='\0'; /* terminate the substring */ printf("Substring <%s> on home row\n",string); } else puts("String does NOT start on home row"); } } Enter your string; EOF to exit dash |Substring on home row chaff |String does NOT start on home row shaft |Substring on home row See also:`strcat(), strchr(), strcmp(), strcpy(), strncat(), strncmp(), strncpy(), strpbrk(), strrchr() `Function Libraries` 4 - 174 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` stty(LIBC) stty(LIBC) This function sets control information concerning a files. _____________________________________________________________ | | | `#include ` | | `int stty( fildes, argp );` | | `int fildes; struct sgttyb *argp;` | | | | fildes - is a descriptor of the file. | | | | argp - is a pointer to the data structure. | |_____________________________________________________________| Description This function sets control information on files. The data to be set is stored in the data structure pointed to by the "argp" argument and has been previously obtained via a call to gtty() or ioctl(). The structure is defined in the "sgtty" header file and is as follows: struct sgttyb { char sg_colctr; /* column counter */ char sg_control; /* control byte */ char sg_flag; /* FCA flag byte */ }; The "sgttyb.sg_colctr" element stores a counter for the current column posi- tion of the output image for the device. This item is relative to zero and is reset to zero when a new-line is sent to the fildes. It is initialized to zero when the filedes is opened. The "sgttyb.sg_control" byte stores various bit fields and is masked as follows: IO_BREAK 0x10 /* mask for #option BREAK */ IO_TABSTOP 0x0f /* mask for "tabstop-1" */ IO_FDCOE 0x80 /* mask for "close_on_exec" flag */ The stty() function is equivalent to: ioctl(fildes,TIOCSETP,argp); TIOCSETP is defined in the "sgtty" header file. The function is typically used to establish tab stops at other than the default of every 8 columns or to establish the BREAK key value as EOF on an input device. Note that for tabs, IO_TABSTOP is one less than the stop value (i.e. for every eight columns, use 7). Return Code If the call was successful, NULL will be returned; otherwise, an EOF will be returned and the global error variable, errno, will contain the UNIX error number associated with the error. See also:`ioctl(), gtty() `Function Libraries` 4 - 175 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` swab(LIBC) swab(LIBC) This function copies bytes from one region to another with swapping. _____________________________________________________________ | | | `void swab( from, to, nbytes );` | | `char *from, *to; int nbytes;` | | | | from - is a pointer to the region to copy. | | | | to - points to the region to copy into. | | | | nbytes - is the number of bytes to swap. | |_____________________________________________________________| Description This function copies "nbytes" from the location pointed to by "from" into the location pointed to by "to", while it exchanges odd and even bytes during the copy operation. The value, "nbytes", should be even and non-nega- tive. The function is typically used to prepare integer data on the host machine for transmission to another machine which uses a reverse order for storing 2-byte words. Example int loop, flipped[5], words[5] = {1,10,100,1000,10000}; char *p; main() { swab(words,flipped,sizeof(words)); fputs("Before swab: ",stdout); p = words; for (loop=0; loop` | | `double tan( argx );` | | `double argx;` | | | | argx - is the angle in radians for which the | | tangent is desired. | |_____________________________________________________________| Description The function obtains the double precision trigonometric tangent of a double precision argument entered in radians. The result is double precision. Example #include stdio.h #include math.h char inbuf[81]; double d1, d2; main() { puts("tan: Enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; d2 = tan(d1=atod(inbuf)); printf("The tangent of %g is %e\n",d1,d2); } } tan: Enter your number: EOF to exit 1 |The tangent of 1 is 1.557408e+00 1.57 |The tangent of 1.57 is 1.255766e+03 1.6 |The tangent of 1.6 is -3.423253e+01 See also:`ftan(), sin(), cos() `Function Libraries` 4 - 181 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` tanh(MATH) tanh(MATH) This function obtains the hyperbolic tangent for an angle in radians. _____________________________________________________________ | | | `#include ` | | `double tanh( argx );` | | `double argx;` | | | | argx - is the angle in radians for which the | | hyperbolic tangent is desired. | |_____________________________________________________________| Description This function obtains the double precision hyperbolic tangent of its double precision argument entered in radians. It returns a double precision result. Example #include stdio.h #include math.h char inbuf[81]; double d1, d2; main() { puts("tanh: Enter your number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; d2 = tanh(d1=atod(inbuf)); printf("The hyperbolic tangent of %g is %e\n",d1,d2); } } tanh: Enter your number: EOF to exit 0.5 |The hyperbolic tangent of 0.5 is 4.621172e-01 1.0 |The hyperbolic tangent of 1 is 7.615942e-01 3.0 |The hyperbolic tangent of 3 is 9.950548e-01 See also:`sinh(), cosh() `Function Libraries` 4 - 182 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` tell(LIBC) tell(LIBC) This function obtains the current position of a file. _____________________________________________________________ | | | `long tell( fildes );` | | `int fildes;` | | | | fildes - is the file descriptor of the file. | |_____________________________________________________________| Description Tell() obtains the current position of the file identified by the file descriptor, "fildes". The function is identical to: lseek( fildes, 0L, 1) and is considered obsolete. Return Code The file's position relative to the beginning of the file is returned as a long integer. See also:`lseek(), open(), creat(), fseek() `Function Libraries` 4 - 183 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` time(LIBC) time(LIBC) This function obtains the UNIX time measured in seconds. _____________________________________________________________ | | | `long time( 0 );` | | | | `long time( tloc );` | | `long *tloc;` | | | | tloc - is a non-zero pointer where the returned | | value will also be stored. | |_____________________________________________________________| Description The UNIX time is defined as the number of seconds since 00:00:00 stand- ard local time January 1, 1970. As long as "tloc" is not zero, the return value is also stored at the location pointed to by "tloc". Example main() { long tod; time(&tod); printf("Time now is %ld seconds since 1/1/70\n",tod); printf(" in ASCII is %s",ctime(&tod)); } Time now is 501780054 seconds since 1/1/70 in ASCII is Mon Nov 25 15:20:54 1985 Time now is 501780066 seconds since 1/1/70 in ASCII is Mon Nov 25 15:21:06 1985 See also:`asctime(), ctime(), localtime(), systime(), sysdate() `Function Libraries` 4 - 184 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` toascii(LIBC) toascii(LIBC) This function is used to convert a character to ASCII. _____________________________________________________________ | | | `char toascii( c );` | | `char c;` | | | | c - is the character under test. | |_____________________________________________________________| Description Toascii() converts the character under test to ASCII by stripping bit_7 from the character passed as the argument. Return Code The function will return the converted character, as required. Example char *p,*input="ThIs Is A f\xf5NnY \xD3tRinG"; main() { p=input-1; while (*++p) *p=toascii(*p); puts(input); p=input-1; while (*++p) *p=tolower(*p); puts(input); p=input-1; while (*++p) *p=toupper(*p); puts(input); } ThIs Is A fuNnY StRinG this is a funny string THIS IS A FUNNY STRING `Function Libraries` 4 - 185 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` tolower(LIBC) tolower(LIBC) This function is used to convert a character from upper or lower case to lower case. _____________________________________________________________ | | | `char tolower( c );` | | `char c;` | | | | c - is the character under test. | |_____________________________________________________________| Description Tolower is used to convert an upper-case character <'A' through 'Z'> to a lower-case alphabetic <'a' through 'z'>. The function affects only alpha- betic characters; numbers, special symbols, etc., are returned unaltered. Return Code The function will return the converted character, as required. Example char *p,*input="ThIs Is A f\xf5NnY \xD3tRinG"; main() { p=input-1; while (*++p) *p=toascii(*p); puts(input); p=input-1; while (*++p) *p=tolower(*p); puts(input); p=input-1; while (*++p) *p=toupper(*p); puts(input); } ThIs Is A fuNnY StRinG this is a funny string THIS IS A FUNNY STRING `Function Libraries` 4 - 186 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` toupper(LIBC) toupper(LIBC) This function converts a character from lower or upper case to upper case. _____________________________________________________________ | | | `char toupper( c );` | | `char c;` | | | | c - is the character under test. | |_____________________________________________________________| Description Toupper() performs the function opposite to tolower(); a lower case character is converted to upper case. The function affects only alphabetic characters; numbers, special symbols, etc., are returned unaltered. Return Code The function will return the converted character, as required. Example char *p,*input="ThIs Is A f\xf5NnY \xD3tRinG"; main() { p=input-1; while (*++p) *p=toascii(*p); puts(input); p=input-1; while (*++p) *p=tolower(*p); puts(input); p=input-1; while (*++p) *p=toupper(*p); puts(input); } ThIs Is A fuNnY StRinG this is a funny string THIS IS A FUNNY STRING `Function Libraries` 4 - 187 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ttyname(LIBC) ttyname(LIBC) This function obtains the file name of the terminal device associated with an open file descriptor. _____________________________________________________________ | | | `char *ttyname( fildes );` | | `int fildes;` | | | | fildes - is the file descriptor for which the | | terminal name is desired. | |_____________________________________________________________| Description This function returns a pointer to the name of the character special file (i.e. device) identified by the file descriptor, "fildes". Warning The returned pointer references static data which is subject to change. Example /* cktty/ccc */ extern char *ttyname(); main() { int fildes; for (fildes=0; fildes<3; fildes++) printf("The name of fildes %d is %s\n",fildes,ttyname(fildes)); } cktty #*pr The name of fildes 0 is *KI The name of fildes 1 is *DO The name of fildes 2 is *PR See also:`isatty() `Function Libraries` 4 - 188 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ungetc(LIBC); ungetch(LIBC) ungetch(LIBC); ungetc(LIBC) These functions can be used to return a single character to a file stream. _____________________________________________________________ | | | `int ungetc( c, stream );` | | `char c; FILE *stream;` | | | | `int ungetch( c );` | | `char c;` | | | | c - the character or byte to un-get. | | | | stream - the file pointer obtained from fopen(). | |_____________________________________________________________| Description The opportunity may present itself where a character that has been obtained via getc() is not needed and should be left available for the next getc() invocation. The ungetc() function can be used to store this character in a one-character buffer associated with the file stream. The ungetch() function is identical to the construct, ungetc(c,stdin);. Note, the scanf() function uses ungetc(). Return Code If the one-character buffer is already storing a character from a prev- ious ungetc(), EOF will be returned; otherwise, NULL will be returned. Warnings The file pointer passed as the stream argument of the function must be one obtained from fopen(). Do not use ungetch(fpup(fildes)) as the block file I/O functions do not utilize the ungetc() buffer. The ungetc() storage is shared with the storage of the last DOS error number encountered. Example /* after newline, strip line feed if present */ if (( c=getchar()) != 'x0a') ungetch(c); `Function Libraries` 4 - 189 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` unlink(LIBC) unlink(LIBC) This function is used to delete a file from disk. _____________________________________________________________ | | | `int unlink( path );` | | `char *path;` | | | | path - the file specification of the file that is | | to be removed. | |_____________________________________________________________| Description This function performs the same operation as the DOS function to delete a file [LDOS - KILL, TRSDOS - REMOVE]. The file must not currently be open in the MC file system. Return Code The return code will be NULL if the file is unlinked without error. A return code of EOF indicates that an error has occurred and the global error variable, errno, will contain the UNIX error number associated with the error. Warning It is an error to try to unlink a file which is currently open [via fopen(), open(), dup(), dup2(), or creat()] in the MC file system and unlink() will not permit the deletion. Example #include main(argc,argv) int argc; char *argv[]; { FILE *fp; if ( argc==1 ) { puts("Usage: testunlk filespec [inhibit]\n"); exit(-1); } if (argc == 3) if (( fp=fopen(argv[1],"R"))==NULL ) { printf("Error in opening %s\n",argv[1]); exit(-1); } printf("Unlink's return code = %d\n",unlink(argv[1])); } `Function Libraries` 4 - 190 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` write(LIBC) write(LIBC) Write() is used to write a block of bytes to a file. _____________________________________________________________ | | | `int write( fildes, buffer, n );` | | `int fildes, n; char *buffer;` | | | | fildes - the file descriptor of the file. | | | | buffer - a buffer containing the bytes to write. | | | | n - the number of bytes (block size) to write | |_____________________________________________________________| Description The write() function will write a number of bytes equal to the "n" ar- gument or until an error in writing is detected. Use lseek() or seek() to position to the start of where writing is to occur. If you are writing se- quentially, a seek operation is not needed. The block size which is optimum for speed of throughput will be a multiple of the file's sector size which is defined as BUFSIZ in the "stdio" header file. Return Code The exact number of bytes written will be returned as the function's return code. If this number does not equal "n", then an error has occurred and the global error variable, errno, will contain the UNIX error number which describes the error. The DOS error number may be obtained with ferror(). Example creat_file(name) char *name; { int i,fd; if ((fd=creat(name,0777))==EOF) open_error(name); for (i=0;i<10000;i++) { if ((write(fd,itoa(i,record),10))!=10) { printf("Error in writing %s\n",name); exit(-1); } cursor(10,3); /* position cursor */ printf("Writing record %5d\n",i); } close(fd); } See also`read(), open(), lseek() `Function Libraries` 4 - 191 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` _xlate(LIBC) _xlate(LIBC) This function obtains the equivalent UNIX error number of a DOS error. _____________________________________________________________ | | | `int _xlate( errnum );` | | `int errnum;` | | | | errnum - is the DOS error number for which the UNIX | | equivalent is desired. | |_____________________________________________________________| Description This is not a standard UNIX function; thus, it is not portable across C implementations. Of course, DOS error codes are not portable, either. The error number may be one obtained from ferror(). The UNIX errors are defined in the "errno" header file. A Unix error may be displayed via perror() or the error message obtained via sys_errlist(). Example main() { int i; for (i=0; i<25; i++) printf("%02d ",i); putchar('\n'); for (i=0; i<25; i++) printf("%02d ",_xlate(i)); } 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 00 04 02 04 04 04 06 04 08 04 02 04 04 04 04 15 16 04 04 16 04 04 04 04 24 See also:`perror(), ferror(), errno, sys_errlist() `Function Libraries` 4 - 192 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` xtoi(LIBC); xtol(LIBC) xtol(LIBC); xtoi(LIBC) This function is used to convert character strings of hexadecimal digits to their integer or long integer value. _____________________________________________________________ | | | `int xtoi( string );` | | `char *string;` | | | | `long xtol( string );` | | `char *string;` | | | | string - is a string containing hexadecimal digits | | <0-9, a-f, A-F>. | |_____________________________________________________________| Description This C function obtains the machine value of a string of hexadecimal digits in character form (i.e. composed of nothing but characters in the range 0-9, a-f, and A-F). Left truncation of the integer value takes place if an excess number of digits is present (i.e. ival=xtoi("10001"); would result in the integer value of 1 decimal). Conversion stops as soon as the first character not in the valid range is detected. Return Code The obvious return code of the xtoi() function is the integer value of the string. The xtol() function returns a long integer. Example #include stdio.h char inbuf[81]; int ival; long lval; extern long xtol(); /* to show that function returns a long */ main() { puts("Enter your hexadecimal number: EOF to exit"); while (TRUE) { if (!gets(inbuf)) break; ival=xtoi(inbuf); lval=xtol(inbuf); printf("Number in decimal (int|long)is: (%d|%ld)\n",ival,lval); } } Enter your hexadecimal number: EOF to exit 1234 |Number in decimal (int|long)is: (4660|4660) 12345 |Number in decimal (int|long)is: (9029|74565) fffff |Number in decimal (int|long)is: (-1|1048575) abcd |Number in decimal (int|long)is: (-21555|43981) 8000 |Number in decimal (int|long)is: (-32768|32768) See also:`atoi(), atol(), btoi(), btol(), otoi(), otol() `Function Libraries` 4 - 193 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` zero(LIBC) zero(LIBC) This function will fill a memory block with binary zeroes. _____________________________________________________________ | | | `void zero( address, length );` | | `char *address; unsigned length; | | | | address - is the starting address of the memory | | region to zero. | | | | length - is the number of memory cells to zero. | |_____________________________________________________________| Description This function is equivalent to "fill( address, length, 0);". Example #define SIZE 4096 main() { char *p, *s; if (!(p=alloc(SIZE))) /* allocate non-zeroed memory block */ abort(); if (!(s=malloc(SIZE))) /* allocate zeroed memory block */ abort(); if (memcmp(p,s,SIZE)) puts("Before zero(): memory compares different"); zero(p,SIZE); if (memcmp(p,s,SIZE)) puts("After zero(): memory compares different"); else puts("After zero(): memory compares same"); } Before zero(): memory compares different After zero(): memory compares same See also:`fill(), memset() `Function Libraries` 4 - 194 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Runtime options and I/O control Runtime options provide flexibility in customizing some aspect of the program which you are developing. Note that the option support provided in MC is not something usually found in other C compilers; or where provided, it would typically be implemented in some other manner (such as forcing you to edit some library or invoke some function other than a standard function). What this means is that when you utilize these options, a little lack of portability is introduced into your C source program. You therefore should adequately document your use of these options so that you may recognize their effects when you choose to port your program to some other system. MC provides a few different facilities for invoking options. The speci- fic facility used depends on the scope of the desired effect. For instance, the "#option" preprocessor directive is usually used to change which library modules are to be included during the link session. The "option()" function is used to alter the behaviour common to the entire I/O package while the "ioctl()" function is used to alter the behaviour of a specific device. In addition, compiler options, such as "+f", alter a particular aspect of the compiler's behaviour. The following sections include material on various options. Some of the material enhances the information provided elsewhere in this document while other material specifically documents the use of an option facility. ERRORMSG The I/O package provided in LIBC has the capability of invoking the DOS I/O error handler when any error is indicated by a DOS service call. This handler uses the "@ERROR" DOS facility. Since the DOS error facility always issues its error message display through the "*DO" device, any display will be irrespective of standard output or standard error output redirection. The default state of "errormsg" is FALSE; thus, any detected error will not ini- tiate a request to the DOS error handler. There will always be some error returned from a library function when a DOS I/O error has been detected regardless of the state of "errormsg". Using the function's error indication, along with any DOS error available via ferror() or the UNIX error variable, "errno", and perror(), your program can obtain some "controlled" error message display. A controlled display is usu- ally more appropriate for an installed program. The error return codes are documented for each function in Chapter 4, "Library Functions", where appli- cable. During program development, you may desire to have the DOS I/O error message displayed automatically upon detection of an I/O error. All you need do is set the "errormsg" flag to TRUE. The state of this flag is altered by coding the option() function as follows: option(O_ERRORMSG,TRUE); within your C source program. The symbolic constant "O_ERRORMSG" is defined in the stdio header file. When an I/O error occurs, the DOS error handler will report an error diagnostic similar to the following: `Advanced Topics - Options` 5 - 1 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ** Error code = 24, Returns to X'363F' ** File not in directory File = NOSUCHF/ILE:7 Last SVC = 102, Returned to X'1A19' BRIEF This option works in concert with "errormsg". The DOS provides a facil- ity for specifying a long or a short (brief) error diagnostic display mes- sage. If the long message identified above is too lengthy, it can be shortened to: File not in directory by invoking the option() function as follows: option(O_BRIEF,TRUE); The symbolic constant "O_BRIEF" is defined in the stdio header file. Note that neither the long error diagnostic nor the short error diagnostic will be displayed unless "errormsg" has been optioned TRUE. KBECHO In certain types of programs, such as screen and graphics editors, the programmer may choose to control the display of characters typed at the key- board. However, for most programs it is desirable to be able to see what is being typed without overt action on the part of the program, even if standard output has been redirected. The "kbecho" option allows this flexibility. When set TRUE, "kbecho" will cause the getc() function (and likewise the getchar() function) to echo all characters input from the keyboard to the video display device (*DO). This holds true for ANY file opened as "*KI", not just the standard input. Since "kbecho" defaults to FALSE, if you desire its effect, you need to set it TRUE by invoking the option function as follows: option(O_KBECHO,TRUE); The symbolic constant "O_KBECHO" is defined in the stdio header file. The state of "kbecho" (i.e. FALSE to TRUE and TRUE to FALSE) may be freely altered while your program is running. BREAK The TRSDOS 6 keyboard driver provides a facility for generating an end of file indication by a specific combination of keystrokes (specifically, <@>). Thus, an EOF can be generated from the keyboard just like an EOF is generated when reading a file stream and the end of the file is reached. Unfortunately, LDOS 5.1 does not have such a capability. Therefore, an option has been provided to enable the key to be used as an EOF indicator. This option is device specific; thus, it is enabled or disabled via the ioctl() function. The option is operational on all MC releases. You should read the documentation on the ioctl() function contained in Chapter 4, `Advanced Topics - Options` 5 - 2 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` "Function Libraries". The "break" option appears in numerous examples throughout chapter 4. WILDCARD The "wildcard" facility in MC provides an automatic search of a disk directory so as to expand a command line wildcard file specification argument into a vector of all file specifications found in the directory which match the wildcard file specification found on the command line. The wildcard file specification is interpreted as containing three fields: a file name, a file extension, and a drive specification. A wildcard file specification uses two special characters significant for matching purposes: the asterisk "*" and the question mark "?". The question mark will match any character in that character position. The asterisk is used to match all trailing characters in that field. When the asterisk is used, it should be the last character in a field (the "last" might also be the "first"). The drive specification field does not accept the two "matching" characters but is considered to be an asterisk if the field is omitted. Since the design of a program must specifically take into account the use of wildcards, the wildcard expander module contained in LIBC is not nor- mally linked to your program. You specify the use of wildcards by adding an "#option" directive to your program such as the following: #option wildcard As is typical with other #option directives, the operand may be upper or lower case. The "wildcard" option directive can also be used to inform the wildcard expander that you want it to ignore checking the first "n" arguments for wildcards. This is accomplished by specifying the directive as: #option wildcard nskip The "nskip" operand is the quantity of arguments that should be skipped. Note that the first argument, argv[0], is always the program name and is never included in the "nskip" count. If no arguments are to be skipped, the "nskip" operand MUST be omitted; do NOT enter it as a ZERO. This argument skipping facility allows you to accept pattern matching arguments on the command line without worrying about them being interpreted as wildcards. The appearance of the "#option wildcard" directive in either form will automatically alter the conditions established in the MC/ASM file so as to link the wildcard expander module to your program during the link session. The typical command line would use one or more wildcard specifications to designate a collection of files for an input stream. Any output generated by the program would need to use the standard output stream which may be re- directed on the command line or reopened within the program by the freopen() library function. A command line could also include "switches" which are usually prefixed by a plus or minus sign. The following rules are used by the wildcard expander in determining whether a command line argument is to be interpreted as a wildcard specifi- `Advanced Topics - Options` 5 - 3 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` cation: 1) The first command line argument is always interpreted as the invoked program name; thus, it is not treated as a wildcard. 2) The next "nskip" arguments encountered on the command line are passed unchanged to the argument list; they are never treated as wildcards. 3) Any argument enclosed in either single quotes or double quotes is NOT treated as a wildcard, regardless of the presence of any wildcard characters (*,?) within the text of the argument. 4) If the first character of an argument is a question mark, the argument is interpreted as a wildcard. 5) If the first character of an argument is an asterisk and the following character is not alphabetic, the argument is interpreted as a wildcard. 6) If the first character of an argument is an asterisk and the following character is an alphabetic, the argument is not interpreted as a wildcard but as a possible devicespec. 7) If the first character of an argument is an alphabetic, then the entire argument is scanned for wildcard characters (*,?). If any are found, the argument is considered a wildcard, otherwise it is passed unchanged to the argument list. Non-wildcard arguments are included in the argument list in their position relative to adjacent arguments. Wildcard arguments force a search of the appropriate directory for matches to the wildcard specification. If the drive specification is omitted from the wildcard specification, the directories of all connected disk drives will be scanned for file specifications which match the wildcard specification. Note that a device specification (the typical device specification is an asterisk followed by two alphabetic characters) is still interpreted as a device specification since an alphabetic following an asterisk will not be interpreted as a wildcard file specification. Note that arguments enclosed within single or double quotes will not be expanded; they are not treated as wildcards. If the command line includes one or more wildcard specifications and no match is found during the directory search(es), the diagnostic message: No files matched wildcard(s) will be displayed and the program will abort. This acts as a safety valve to a program which could not function since no input file specification was provided. The following test program can be used to illustrate the expansion ef- fects of various command lines which include one or more wildcards. `Advanced Topics - Options` 5 - 4 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` /* * WILDTEST/CCC - test "built-in" wildcard arg expander */ #include #option WILDCARD int i; main(argc, argv) int argc; char *argv[]; { printf("argc: %d, argv: %#04X\n\n", argc, argv); for (i = 0; i < argc; ++i, ++argv) printf("argv[%4d]: %#04X is '%s'\n", i, *argv, *argv); } The following program reads a collection of assembler source files and writes to the standard output, all lines which begin with a comment indicator (the semicolon). The wildcard expander makes it easy to specify the collec- tion of "*/ASM" files on a particular drive for use as input. #include stdio.h #option wildcard char buffer[81]; main(argc,argv) int argc; char *argv[]; { while (--argc) /* while there is still an input spec */ { if (!freopen(*++argv,"r",stdin)) /* attempt to open it */ { fprintf(stderr,"Unable to access %s\n",*argv); continue; } while (gets(buffer)) /* while the file still has input lines */ { if (*buffer == ';') /* if a comment, then output it */ if (puts(buffer)==EOF) /* continue if no output error */ exit(-1); /* error exit */ } } } Compiler "float" option K&R is quite specific concerning the operational characteristics of floating point numbers. In paragraph 6.2, they state, "All floating point arithmetic is carried out in double-precision; whenever a float appears in an expression it is lengthened to double by zero-padding its fraction." What this means is that double precision floating point arithmetic is the norm for a standard C compiler. The type of float is available only to limit the storage of floating point numbers; arithmetic is carried out in double pre- cision. Thus, C dictates an automatic upward conversion of floats to doubles for calculations. Furthermore, in paragraph 10.1 concerning the parameter list of a function, they state, "C converts all float actual parameters to double, so formal parameters declared float have their declaration adjusted to read double." `Advanced Topics - Options` 5 - 5 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` What these preceding statements mean is that a standard C compiler has no facility for calculating with single precision floating point; double precision is the standard. MC follows this standard; however, since MC is targeted for a machine environment which is necessarily slow in performing double precision floating point calculations, an option has been provided to specify a non-standard single precision floating point mode. Bear in mind, this option is not without headaches. Great care must be exercised in its use. You also must thoroughly understand the behaviour of the compiler when dealing with the arguments of a function. Since any float argument to a function is always converted up to a double, none of the single precision functions provided in the math library [fabsf(), fatn(), fcos(), fexp(), ffix(), fint(), flog(), fraise(), frnd(), fseed(), fsin(), fsgn(), fsqr(), ftan(), and ftoa()] may be used in the nor- mal compiler mode. You cannot explicitly cast a float argument to a float and override this upward conversion. The default compiler mode for floats is to treat them as doubles in three places: (1) When used in a complex expression. (2) When passed as actual arguments to functions. (3) When declared as formal arguments in function definitions. The "+f" option disables all three. It also causes floating point constants to be treated as float, not double, thus causing a (possible) loss of preci- sion. It also allows you access to the much faster single precision floating point functions (with a resultant loss of accuracy). The "+f" compiler option does not prevent you from using any double precision function or performing any complex expression evaluation which mixes floats and doubles; floats will still be upgraded to double when in an expression with a double (see the arithmetic conversion specifications noted under "binary operators" in Chap- ter 2). Explicit casts to float or double may thus be necessary in certain places. For instance, the various print() functions ALWAYS expect a double for a floating point argument. If you have invoked the "+f" compiler option and pass a float as a print() parameter, you must explicitly cast it to a double since the compiler will no longer do this for you. All this boils down to a couple of observations: (1) Use this option sparingly; only when lower precision is acceptable and/or when faster execution is desired and/or when code/data space is at a premium. (2) The generated code is obviously non-portable. (3) Mixing of doubles and floats is not recommended. (4) The need for casts forces the code to get somewhat tricky in places. `Advanced Topics - Options` 5 - 6 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Call: DOS SVC interface You will usually find the C langauge useful in writing DOS utility pro- grams which extend the capabilities of the DOS just like the DOS provided library commands. Such utility programs may need direct access to DOS service calls. Since these types of programs are DOS specific in nature, there is usually no need to worry about portability aspects; however, it is always wise to provide some standardized method of isolating the non-portable DOS interface. Thus, the programmer has been provided with a function in the installation library which provides a level of standardization. This is the call() function. The call() function has been provided in the installation library to standardize the invocation of machine language routines and DOS service calls. The use of call() is thoroughly documented in Chapter 4, "Function Libraries". The call() function saves the state of the index registers, IX and IY, during its execution; thus, there is no restriction on its use. Note that the function will invoke either a system SVC or directly CALL a machine address based on the "address" parameter value passed in the function's invocation. That means that even in an SVC interfaced DOS, it is still pos- sible to use call() to execute and return from a memory resident machine language module which is external to the C program's environment. Separate Compilation of Modules MC supports separate compilation: functions and modules can be compiled at different times, assembled separately, then linked together to produce one program. This facilitates the creation of relocatable module function li- braries, and results in great time savings. Commonly used functions can be compiled and assembled once, then only linked into new programs, without re- compiling or assembling. Large programs may be segmented and each segment compiled and assembled separately, then linked as a whole by the linker. With the "extern" and "static" statements, the variables used in a module may be specified as external or local. When separately compiling modules which reference variables in other modules, there is only one approach which may be taken to supply declarations for the shared variables. That approach, which is the proper method and re- sults in better structure in programs, is to define variables as extern when referenced by all but one of the modules with that one module defining the "public" variables outside of all functions that it contains. To illustrate the mechanics of separate compilation, consider a large program which has been broken up into four separate C source files. The files are: "progmain", "progio", "progmenu", and "progwork". Each of these files may be compiled with a JCL command line such as: DO MC (N=progname,C) The JCL parameters specify the name of the file to be compiled (N=progname) and the compile option (C). After the JCL has been invoked for each of the C source files, this results in four assembly output files. Following the com- pilation phase, the three subordinate files ("progio", "progmenu", and "progwork") can each be assembled to a separate relocatable module with a `Advanced Topics - Separate Compilation` 5 - 7 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` command such as: MRAS progname -NL M80 progname=progname which results in the generation of a /REL file with the same filename as "progname". The "progmain" file which includes the main() function would be assembled with a command line such as: MRAS MC +I=PROGMAIN +O=PROGMAIN -NL M80 prognameprogname The difference in this MRAS invocation is that the MC/ASM file is the primary file to be assembled with "progmain" as an "INCLUDE" file. The "+O=PROGMAIN" is used to override the default output file name with a specific designation of "PROGMAIN". The "progmain" file could also be compiled and assembled in one command step via the JCL command string previously shown by adding the JCL parameter, "A", as in: DO MC (N=progname,C,A) The subordinate files cannot be compiled and assembled in one JCL command step with the MC/JCL file supplied; however, it could be done by altering the MRAS invocation command line in the JCL file to appear like the first illus- tration. Once all of the four files have been compiled and assembled, you gene- rate the executable command program with the linker. To continue with this illustration, an appropriate link command would be: MLINK PROGMAIN,PROGIO,PROGMENU,PROGWORK-N=PROG:d-E L80 PROG:d-N,PROGMAIN,PROGIO,PROGMENU,PROGWORK,-E:M80BGN where the ":d" would be replaced with the output drive specification. The resulting executable command file would be named "PROGMAIN/CMD". Obviously, the rationale for using this separate compilation approach would be to limit your development efforts to more managable "chunks" of code. You would rarely be working on all of the files simultaneously but would most likely complete the development of a subordinate module (compile and assemble steps) prior to continuing on with the remaining modules. This provides a scheme of partitioning your program into a sequence of small de- velopment efforts. An alternative method of partitioning a large program into small "chunks" would be to isolate every function into a separate file. Compile and assemble each function individually. Write small test programs to exercise each function separately, then build a library, say PROGLIB", with the relo- catable function modules. Your "progmain" could then just declare an "#option PROGLIB" to search the library during the link process. See the section on "Building and Maintaining Relocatable Libraries" in this chapter. `Advanced Topics - Separate Compilation` 5 - 8 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Using extern and static When writing a large program, it is best to try to logically structure your program into modules containing related functions with the data struc- tures they use within the same module. Any functions or non-automatic data structures in a module which need not be accessed by any external function can be declared as "static". These static functions and variables will be unique in name when compiled and assembled, and will not be accessible to other modules; thus, there will be no conflicts in naming. Those functions and non-automatic data structures declared in the module which need to be accessed by functions in other modules should be declared without any storage class. This causes these functions and data structures to become "public", meaning that they are defined in this module, and can be accessed from other modules. When a module uses a function or data structure declared in another module, the "extern" statement is used to declare the type of the object. "extern" is required for accessing variables outside the module. However, if a function is used without an "extern" declaration, the compiler will assume that the function returns an integer value. If any other result is returned, the function must be declared "extern" with the appropriate type. A few examples may help you appreciate the distinctions being addressed here. Spend a little time studying the C source code declarations in the following module until you understand the accessibility of each variable. int var1; /* public to all functions of all modules */ static int var2; /* accessible to functions which follow in this module: main(), func1(), func2() */ main() { static int var3;/* local to main only */ int var4; /* local to main only */ } int var5; /* public to all functions of all modules */ static int var6; /* accessible to functions which follow in this module: func1(), func2() */ func1() { int var7; /* local to func1 only */ static int var8;/* local to func1 only */ } static int var9; /* accessible to functions which follow in this module: func2() */ func2() { ; } `Advanced Topics - Using extern and static` 5 - 9 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` The variables "var1" and "var5" become public to all modules because these variables are defined outside of all functions of this module and are also not defined with a storage class. Thus, some other module may access these two variables if that other module includes the statement, extern int var1, var5; Now even though "var2", "var6", and "var9" are variables defined outside of all functions in this module, since they have the storage class "static", they become accessible only to the functions within this module. In fact, note that a static variable defined outside of a function becomes accessible only to the functions which follow the declaration. Thus, "var2" is access- ible to main(), func1(), and func2(); but "var6" is accessible only to func1() and func2() since it is declared following main(). Static variables declared inside of a function are still local only to that function. The primary difference between a static and an auto is that a static has a specific memory storage assignment whereas an auto's storage is strictly on the stack. Statics are generally accessed faster than autos; thus, if speed is important, consider the use of statics. The contents of such static variables also persist across repeated calls to the same function. `Advanced Topics - Using extern and static` 5 - 10 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Building and Maintaining Relocatable Libraries We encourage C users to create libraries of commonly used functions. This increases your productivity, since functions need not be rewritten for each program. A library should contain functions which are self-contained; i.e, they do not require the calling function to know about the library mod- ule's internal structure, and do not assume anything about data structures that the calling function declares. In structured programming lingo, library functions should be data-coupled and functionally cohesive. Also, functions should be tested and be well debugged before being placed in a function library. The first point to make concerning relocatable libraries is that the filename field of a library file specification cannot exceed seven charac- ters. The second point is if you name your library "USERLIB", you need take no further action after you have built the library. If you are using the MRAS assembler package, building a library is very easy since you have the MLIB relocatable module librarian. MLIB is used to build and maintain relocatable libraries. If you have no library of your own already built, you start off just by using the "load library" MLIB command and load a compiled and assembled function (a module). You can continue to add additional compiled and assembled function modules via the "add module" MLIB command. The library is "built" in memory as the modules are added; then you write it to disk via the "save library" MLIB command. If you are using the M80 assembler package, you may not have access to a convenient librarian such as MLIB. Thus, you must build your library sequen- tially by appending modules together using the APPEND library command pro- vided with your DOS. Any number of functions can be added in this fashion; however, since you have no facility to extract or rearrange the library mod- ules, remember to save a copy of each module individually on an archive disk. When you use the APPEND command to add each module, use the STRIP parameter of APPEND to remove the end of file byte (X'9E') from the library file when you are appending a module to the library. For instance, if you want to build a NEW library composed of three modules named "eenie", "meenie", and "minie", the sequence of commands would be like the following: COPY EENIE/REL USERLIB/REL APPEND MEENIE/REL USERLIB/REL (STRIP) APPEND MINIE/REL USERLIB/REL (STRIP) The first command is used to copy the first module into a new file called "userlib/rel". The subsequent APPEND commands will append the second and third modules to the "library" while the use of the "strip" parameter tells APPEND to backspace over the last byte of the library file (the X'9E) before appending the new module. A library is normally searched by the linker sequentially from beginning to end unless the library is constructed as an "indexed relocatable" library (IRL) by the MLIB librarian. Therefore the order in which functions are placed in the library becomes important. If a function of a module in the library is called by another function in another module within the library, then the calling function's module must appear first. This is because the external reference for the called function will not be sensed until the `Advanced Topics - Libraries` 5 - 11 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` calling function is linked. So the general rule is: Calling functions first, called functions last. Note that in the above discussion, it was recommended that you name your library "USERLIB/REL". That's because there are two files provided with the MC package which need to be adjusted depending on the name and quantity of user provided libraries. The first file which needs modification is the MCMACS/??? file (where ??? could be ASM or MAC depending on the assembler you are using). For each user provided library you want to have searched, the definition, @_LIBRARYNAME DEFL 0 must be added to the list of "established defaults". In the following excerpt of the provided file, ; establish defaults for MC options @_MATHLIB DEFL 0 @_INLIB DEFL 0 @_ARGS DEFL -1 @_REDIRECT DEFL -1 @_FIXBUFS DEFL 0 @_MAXFILES DEFL 13 @_USERLIB DEFL 0 note that the declaration for a "userlib" library has already been inserted (the seventh line). There is no requirement for any specific position of the declaration in this file. It can be placed anywhere. The other file which needs to be altered is the MC/??? file. This file must include the statements: `IF @_LIBRARYNAME `$REQ LIBRARYNAME `ENDIF Contrary to the insertion into the MCMACS/??? file, the positioning of these statements is very important in the MC/??? file. The following excerpt of the provided MC/??? file shows that the statements needed for a library named "userlib" have already been included. LD HL,0 ;Set return code PUSH HL CALL EXIT ;Back to DOS IF @_USERLIB ;TRUE if #option USERLIB $REQ USERLIB ENDIF IF @_MATHLIB ;TRUE if #option MATHLIB $REQ MATH ENDIF IF @_INLIB ;TRUE if #option INLIB $REQ IN ENDIF $REQ LIBC ;Standard lib always! $REQ LIBA ;Run-time lib always! `Advanced Topics - Libraries` 5 - 12 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` The "$REQ" assembler macro statement passes a request to the linker to search the designated library. Note that the "userlib" request precedes those for MATH, IN, LIBC, and LIBA. This means that your "userlib" is searched before any of the MC provided libraries. It was stated above that calling functions must precede called functions in a library. Likewise, it is also mandatory that a library which has functions that call functions in another library must be searched prior to the library which contains the called functions. This means that the functions in your library have access to all of the functions in MATH, IN, LIBC, and LIBA but that no function in those libraries can "call" any of your user provided functions. The order of library requests is significant when you want to provide a second user library, say MYLIB. If the request statements for MYLIB are in- serted into MC/??? prior to the statements for USERLIB, then no function in "userlib" can call a function in "mylib" but functions in "mylib" can call functions in "userlib". These restrictions could be overcome by adding multiple library search requests during a manual invocation of the linker; MLINK or L80. Programs with overlays MC provides a support function and interface control for the development of a complex program environment involving a root program and one or more overlay programs. The generation of the root and overlay files requires the use of the MLINK linker provided with the MRAS assembler development system. Depending on the total size of the relocatable modules making up the root and the overlays, you may need to invoke the virtual memory facility of the linker. This is discussed in the linker documentation. The design of a C program environment which uses overlays is a complex procedure. It will certainly be difficult to provide an in-depth analysis of all details con- cerning the design of such a complex program environment. This section will cover only the mechanics for the procedure, not the underlying rationale behind the design of such a complex program. In general, a root module contains all of the functions and external variables which must be accessible to the root and all overlay modules. The root module contains the function, main(), and also must contain the overlay handler provided in the IN/REL installation library, execovl(). Each overlay module must contain a similar "main" function called ovmain(). Your job is to decide how your program environment is to partition itself into a root and overlay modules. In order to accomplish this, you need to understand exactly what overlay support is provided. To begin with, there is absolutely NO facility provided for the auto- matic loading of an overlay when a function is called. Your program MUST know it wants to access a given overlay. An overlay is loaded and executed only as the direct invocation of the C overlay handler, execovl(). Next, the root module does not have knowledge of any variable that is a part of any overlay module. Neither does any overlay module have any knowledge of any variable that is a part of another overlay module. On the other hand, every overlay module has total knowledge of "public" variables declared in the root module provided they are declared "extern" in the overlay. Remember from the dis- cussion of external variables in the section on separate compilation, "pub- lic" variables are variables declared outside of all functions of a module `Advanced Topics - Programs with Overlays` 5 - 13 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` and declared without a storage class. The functions of an overlay must still declare such variables "extern" to be able to access them. The execovl() function will call an overlay from the root program. This function is used to invoke an overlay of the executing C program and option- ally pass an argument list to the called overlay. Duplicating somewhat the information on execovl() from Chapter 4, it is defined as follows: _____________________________________________________________ | | | `int execovl(ovnum, ovargc, ovargv);` | | `char ovnum; int ovargc; char *ovargv[];` | | | | ovnum - the requested overlay number in ASCII. | | | | ovargc - the quantity of args to be passed to the | | overlay in the ovargv array. | | | | ovargv - a pointer to the argument vector which is | | to be passed to the overlay. | |_____________________________________________________________| The argument vector "ovargv" MUST have ovargc pointers in it. The "ovargc" and "ovargv" will be passed as arguments to the overlay's ovmain() function in that order. Note that "ovargc" and "ovargv" are optional. NULL will be returned if the requested overlay loaded and executed, otherwise EOF will be returned and errno will be appropriately set. The options O_BRIEF and O_ERRORMSG will be in effect, if set, when such an error occurs. Note that any return code from ovmain() is ignored; you can use pub- lic memory location(s) in the root for communications from the overlay. Your root program can be preprocessed, compiled, and assembled as usual with two exceptions. First, all library routines (i.e. functions provided in MATH, IN, or LIBC as well as runtime routines in LIBA) which are to be common across the overlays MUST be declared "extern" in this root program regardless of whether or not the root makes use of them. The library routines needed by a program may be ascertained by manually linking (i.e. not via Job Control Language) the program with the libraries, specifying the library searches explicitly, then obtaining a symbol table listing which will include all public symbols. Second, the C source module must include the directive, #option root This statement passes information to the MC/ASM file during the assembly phase of your root program. The file, OVTEST/CCC, which follows, contains a fully functional sample root program. /* OVTEST/CCC - overlay test root */ #option INLIB /* used to obtain execovl() */ #option root extern int execovl(), printf(); int ovargc = 3; char *ovargv[3] = { "ovtest", "this is overlay" }; main() { ovargv[2] = "1"; if (execovl('1', ovargc, ovargv)) error(); `Advanced Topics - Programs with Overlays` 5 - 14 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` ovargv[2] = "2"; if (execovl('2', ovargc, ovargv)) error(); } error() { perror("ovtest"); exit(1); } The overlay programs MUST each have a public function called ovmain(), which will be the entry point to each overlay. They each can be preprocessed, compiled, and assembled as usual with one exception. The directive, #option overlay must be included in the C source module of each overlay. The following file, OVERLAYT/CCC, contains a sample overlay program. /* OVERLAYT/CCC - overlay for OVTEST */ #option overlay ovmain(argc, argv) int argc; char *argv[]; { printf("%s: %s %s\n", argv[0], argv[1], argv[2]); } Obviously, with an understanding of the preceding discussion, it becomes obvious that you must compile and assemble the program and its overlay mod- ules separately. The procedure produces a relocatable module for the root and one for each overlay. The link session will then utilize the overlay genera- ting capabilities of the MLINK linker to produce the proper executable root command and overlay files. Thus, the linker will need to be operated manually (without the benefit of the provided MC/JCL Job Control Language file). The link session used to generate a root program from ovtest and two overlay programs using overlayt (using the same module twice just for the purpose of illustration), is as follows: . Link OVTEST etc. to OVTEST/CMD,OV1,OV2 mlink -l=2600 -a=y ovtest -o overlayt -o overlayt -n=ovtest -e //exit In general, the link session must be in something like the following order: MLINK ? -v=:4 ...................> optional; preferably a RAM drive! ? root_program_rel_file(s) ? -S=necessary_library_1 ? -S=necessary_library_2 ... ? -S=necessary_library_n ? -O overlay_1_rel_file(s) ? -O overlay_2_rel_file(s) ... ? -O overlay_n_rel_file(s) ? -N=program_name ? -E `Advanced Topics - Programs with Overlays` 5 - 15 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` When Things Go Wrong C is a language which offers great flexibility, but not without a price. The price of C's freedom is the programmer's ability to make catastrophic errors with ease. The programmer is not protected from himself when using C. Your best protection is to carefully check your programs when you write them, for any evident errors before you try to run them. Of course, any time you test a program you should not have any disks in your drives that you would care about if they were suddenly erased. This is not to say that you should limit experimentation; quite the contrary. However, always be prepared for the worst. With MC, you have an advantage over some other compilers. MC generates an assembly language source file. You can debug the program without trying to second guess the compiler, or having to disassemble the compiled output. The modularity of the program also helps, since there are clear interfaces (functions) to breakpoint at. It would be helpful, though not essential, for the programmer to have familiarity with the Z-80 instruction set and with the debug facility of DOS. Debugging Techniques One of the most direct methods of debugging a C source program which compiles, assembles, and links without error, yet produces incorrect or un- expected results, is to liberally sprinkle the C source code with printf() statements. These "debugging" statements can usually be contained within a preprocessor "#if DBUG ... #endif" directive. By using this method, you can conveniently eliminate the debugging printf() statements after you have cor- rected the problem by undefining the DBUG symbol. This saves you a lot of editing. In fact, it is highly useful to design such debugging printf() statements into your program to begin with, rather than wait until you need to debug unexpected results. If you feel the need to step through the program's execution with the DEBUG utility provided with the DOS, it is recommended that you obtain the appropriate DD&T package to complement DEBUG. This package adds an online disassembler to DEBUG's display. With a good debugger at your disposal, a copy of the symbol table produced by the linker, and the assembly listings appropriate to the modules you wish to debug, you should be ready to inves- tigate the behaviour of your program. Since machine code debugging is a lengthy and brutal experience, it is strongly recommended that you first go back to your C source listings and triple check your coding and algorithms. Also verify the proper checking for error codes returned by functions. Your C source listing is the best place to start your efforts. Compilation Errors MC generates an error message whenever it finds something in the input file that cannot be recognized, or that doesn't fit the syntax of the C language. When MC outputs an error message, it should print the line in error and point to the particular character where the error was recognized. It also displays the line number of the file currently being processed as well as the line number of the function currently being processed. This helps you locate `Advanced Topics - Error Handling` 5 - 16 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` what statement in your source stream is being flagged as containing an error. The actual programming error may be earlier in the program, depending on the type of error. Some errors may not be detected until many lines later. For example, if a closing brace is missing in the input file, MC will not be able to detect the error until the next function declaration, which will then be flagged as a function call without an ending semicolon. This is because MC thinks the previous function has not been completed. Similarly, if an opening brace is missing, MC may not find out until the last closing brace is encountered, with no match. In the appendix of this manual is a list of the error messages which MC can generate, and some likely causes for each. Most errors are usually typo- graphical, but the user should be well versed in the C language and the MC implementation. Learn where to find information regarding syntax and capa- bilities of the language. The language definition chapter of this manual and the appendix of the K&R text are good places to look when you are not sure of syntax. Assembly errors There are few assembly errors which can occur if you assemble your pro- grams using MC/??? with your compiled C modules. Your safest bet is to use MC/JCL when compiling, assembling, and linking. If you have written portions of your program in assembly language you may have a few more errors to deal with. Please read the section on assembly language interfacing for hints in debugging your assembly language. If you are creating a CMD file directly from the MC/JCL file, you will be aware of an assembly error if the JCL aborts from MRAS. To specifically isolate the assembly error, you will need to invoke MRAS without the "-NL" switch. The most direct way to accomplish this is to list the SYSTEM/JCL file (the one which is generated from the MC/JCL invocation) and examine the line which invoked MRAS. It may look something like this: MRAS MC +I=YOURPROG/ASM +O=YOURPROG/CMD -NL At the DOS Ready prompt, all you need do is input the line modified as follows: MRAS MC +I=YOURPROG/ASM -WE -NC When the assembler is invoked in this manner, it will pause when an error is detected. One of the following two errors should usually prevail. UNDEFINED SYMBOL - A symbol which you referenced in your program was undefined in any module in your program. This can be caused by omitting the definition, misspelling the identifier, or defining them incorrectly. A look at the name which is undefined will give you a clue as to which situation was the cause. Misspelling should be obvious. Look out for upper-case versus lower-case names. Remember that C is case sensitive. `Advanced Topics - Error Handling` 5 - 17 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` MULTIPLE DEFINITION - A symbol was defined twice with the same name. If you are assembling separately compiled functions, you may have named two external variables or functions the same. To correct this, make one or both of the identifiers static within the module. If separate compilation is not being used, you have defined two external objects in your program with the same name. It is useful to familiarize yourself with the section on MC assembly language output structure. Also, if you are assembling separately compiled functions, a good understanding of the "extern" statement and external versus static variables is essential. Refer to the section on storage classes in Chapter 2, MC Language Definition. Linker errors The linker errors which you may experience may be limited to the fol- lowing three errors. A "Symbol table overflow" error could be experienced when you are linking a large C program. If you are using MLINK, you should attempt to relink your program using the virtual memory switch. You also could experience a "Multiply defined symbol" error. This means that you have either defined the same public symbol in two different modules or that you have defined as public, a symbol already defined in one of the provided library functions. This is an easy problem to correct in your program. The third error would be "Undefined symbol". This would arise from a symbol de- clared as "extern" in one of your C source files but no module defined the symbol. It may be a spelling error or a programming oversight. Runtime Error trapping As stated in the section on Runtime Error Control in Chapter 1, MC pro- vides certain facilities for the detection and control of four types of run- time errors: DOS I/O errors, C environment errors, low-level floating point errors, and high level floating point mathematical errors. The facilities at your disposal to detect and trap the first two types should be obvious to you after even a brief perusal of Chapter 4, Library Functions. That's because DOS I/O errors and C environment errors are indicated by an error return code passed back from a function call. The following methods are available to your program for displaying I/O errors: 1) Enable the ERRORMSG option via "option(O_ERRORMSG,TRUE);" as discussed earlier under Runtime Options. This provides automatic display of an error diagnostic message when a DOS I/O error occurs. 2) Use the ferror() function to obtain the DOS error code from the stream and act on that code accordingly. You can introduce your own messages as appropriate. With ERRORMSG set to FALSE, your program controls the error diagnostic display. 3) Use the perror() function to obtain the UNIX error message `Advanced Topics - Error Handling` 5 - 18 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` associated with the error. Remember that every DOS I/O error code is automatically translated to a corresponding UNIX error number which is stored in "errno". If you desire portability, you should restrict your error handling to the use of "errno" and perror(). A discussion covering specific methods of dealing with these errors is beyond the scope of this document. The C environment errors will only be reported via an error return code from a function call with "errno" set to the appropriate UNIX error number. Thus, these types of errors can be displayed by method (3) shown above for DOS I/O errors. You don't have to use perror(). Your program can still invoke its own messages in its own manner based on the error code contained in "errno". Since the detection and control of low-level floating point errors is an implementation specific entity, this topic will be discussed in a little more detail. All of the low level math routines which operate on floats or doubles, (i.e. those that perform addition, subtraction, multiplication, division, etc.) exit through a common routine which sets "errno" to an appropriate error number if the routine's return code is non-zero. The only math routines which provide a non-zero return code are the single and double precision floating point routines. When errno is set, control is passed to a floating point vector, called "_fltvec". This normally vectors to an assem- bler RET op code. Thus, when such a low-level floating point error is detected, nothing unusual happens other than the setting of "errno". If your C program wants to take control when such an error is detected, your program only needs to replace the default "_fltvec" vector with the ad- dress of your handler function. The following header file illustrates a low- level floating point handler called "floaterr()" which can display an error message appropriate to the detected error. It includes a function which is called from main() named "initflterr()". This function replaces the "_fltvec" vector with the address of the "floaterr()" handler. Examine closely the behaviour of the various parts of the header file. /* * FLOATERR/H - general floating point error routine - 01/07/86 */ #include /* needed for definitions */ void floaterr(), initflterr(); extern int _fltvec; /* kludge to declare _fltvec */ static char codes[] = /* error codes returned by math routines */ { 0, UNDERFLOW, DOMAIN, OVERFLOW, DIVBY0 }; static char *msgs[] = /* appropriate error message strings */ { "No error", "Underflow", "Illegal function call", "Overflow", `Advanced Topics - Error Handling` 5 - 19 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` "Division by zero", "Unknown error" }; /* * Initialize floating point error routine - call from main() */ initflterr() { _fltvec = floaterr; /* set error vector */ } /* * Routine to trap floating point error */ floaterr(retaddr) unsigned retaddr; { unsigned *sp; int i; sp = &retaddr; /* get stack pointer */ for (i=0; i< sizeof codes; ++i) /* search table, if not found i = 5 */ if (codes[i] == errno) break; fprintf(stderr, "\nFP error %2d (%s), Trace: %04x, %04x, %04x\n", errno, msgs[i], *(sp - 1), *sp, *(sp + 1)); } There is no way to recover the name of the routine which returned the error; you can only detect the error number. It is beyond the scope of this document to provide any additional material for such purposes. The following example illustrates a program which uses this header file. The diagnostic error mes- sages displayed upon running the example are also noted. #include #include main() { initflterr(); /* set error vector */ 1. / 0.; /* division by zero */ 1.701411e+38 * 1.701411e+38; /* overflow */ 1.701411e-38 * 1.701411e-38; /* underflow */ } FP error 7 (Division by zero), Trace: 5455, 31d8, 0000 FP error 3 (Overflow), Trace: 5455, 31ea, 4986 FP error 4 (Underflow), Trace: 5455, 31fc, 4c82 MC also supports the high-level mathematical function error exception reporting as documented for UNIX System V. In this facility, when errors are detected by certain high-level functions, they will invoke the matherr() function in a structured manner. The supplied matherr() function is a NULL function; it does nothing. The high-level error handler will, however, print an appropriate diagnostic message to the standard error file when an error occurs. If you supply your own matherr() function, you can disable the system's message display as well as provide your own error handling. `Advanced Topics - Error Handling` 5 - 20 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` When matherr() is called, a pointer to the exception structure as de- fined in the math header file is passed as an argument. This structure includes the following members: int type; - type of error char *name; - pointer to name of function where error ocurred double arg1, - first argument with which *name was invoked arg2, - second argument with which *name was invoked retval; - default value returned by the function The member named "type" contains the error number which describes the error. The following list of symbolic constants, defined in the math header file along with the system's standard error messages, shows the possible error numbers. DOMAIN - argument domain error SING - argument singularity OVERFLOW - overflow range error UNDERFLOW - underflow range error TLOSS - total loss of significance PLOSS - partial loss of significance DIVBY0 - divide by zero The member "name" points to the actual name of the function which de- tected the error. The following list of functions report errors through matherr(): exp(), log(), log10(), pow(), sqrt(), asin(), acos(), atan(). This list may not be all inclusive. The members "arg1" and "arg2" contain the first two values of the argu- ments of the function which was invoked. Obviously, if the invoked function has only one argument, then "arg2" is irrelevant. The "retval" member will contain the value which the invoked function will return to the calling function. If you want to change that value, all you need do is assign a new value to the structure member. The matherr() function has the following invocation syntax: _____________________________________________________________ | | | `#include ` | | `int matherr( x );` | | `struct exception *x;` | | | | x - is a pointer to the exception structure | | defined in the math header file. | |_____________________________________________________________| The return code from matherr() is used by the system. If matherr() returns a non-zero value, the normal error message printed to standard error by the math error handler will be suppressed and the global error variable, "errno", will not be altered. On the other hand, if your matherr() function returns a zero value, the system's error message will be output normally and "errno" will be set to the appropriate error number. `Advanced Topics - Libraries` 5 - 21 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Some of the example programs provided as illustrations of functions in Chapter 4, Function Libraries, depict various implementations of a matherr() function provided by the program. The examples for exp(), log(), and log10() provide no matherr() function so the system supplied error messages, "Over- flow range error" and "argument domain error" are displayed. Make note of the matherr() functions provided in acos(), asin(), and sqrt(). An example of a more involved and complex matherr() function is illustrated here. This version traps domain errors which would occur from passing a negative argu- ment to sqrt(). The example "fixes up" the error by assuming that the argument to the square root function should have been positive. Pay attention to the method of altering the value to be returned by the high level math function by assigning a new value to "x->retval". matherr(x) struct exception *x; { fprintf(stderr,"Type %d function error in %s...\n",x->type,x->name); fprintf(stderr," Args = %g,%g: ",x->arg1,x->arg2); if ((x->type==DOMAIN) && (!strcmp(x->name,"sqrt"))) x->retval= sqrt(-x->arg1); return TRUE; } Assembly Language Interfacing Since we encourage the programmer to use 100% C source code in the gen- eration of a program, no attempt will be made to document any assembly lang- uage interface to library modules. The barest minimum is provided to assist the experienced assembly language programmer who desires to include some as- sembly language control into his C programming. The programmer who wishes to learn more about the interface between the C language and the provided li- braries would be best advised to examine the compiler's assembly language output from compilations of various C source statements. The caution to be observed is that this output may not be consistant across future releases of the compiler. While it is possible to insert assembly language source code directly into your C program using the "#asm-#endasm" construct, it is much cleaner to interface by placing your assembly language code into a separate module. This keeps all the non-portable code separate from the portable C code. It is best to call assembly language as a function, rather than including it directly into a C function by mixing C and assembly source code in line. `Advanced Topics - Libraries` 5 - 22 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Program Memory Map MC programs, once assembled and linked, have the following utilization of available memory: _____________________________________________________________ | | | $DBEG - Established as the program's LINK ORIGIN | | [or $CBEG] during the link process. This will be the | | lowest machine address used by the program. | | | | $START - Program execution begins here. This is an | | ENTRY within the MC/ASM file. | | | | - MC generated modules. | | | | - In-line assembly language modules. | | | | - Static variables and strings intermixed | | within modules. | | | | - Library modules from USERLIB/REL, IN/REL, | | MATH/REL, LIBC/REL, and LIBA/REL. | | | | ($MEMRY) - Highest machine address used by the program | | and the static variable storage. | | | | ($FREEP) - Contains first machine address available | | for dynamic memory allocation. | | | | - Memory allocated by sbrk(); in use by the | | program, or maintained by alloc(), malloc(), | | calloc(), and free(). | | | | ($LOMEM) - Unused memory available from alloc(), | | calloc(), malloc(), or sbrk(). | | | | (SP-1024) - Memory reserved from dynamic allocation for | | use as program stack space. Local variables | | are stored here. MC always reserves space | | for the program stack when requests for | | dynamic allocation of memory are made. | | | | (HIGH$) - Original CPU Stack Pointer. | |_____________________________________________________________| `Advanced Topics - Assembly Language` 5 - 23 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` MC Identifier Output The following table outlines the format of label generation from MC: _____________________________________________________________ | | | Identifier Class MC Output | | -------------------------------- ----------------- | | | | Local labels $?# | | | | External identifiers NAME | | -longer than 3 characters NAME | | -3 characters or less NAM$ | | | | Static identifiers | | -external to functions Same as externals | | -internal to functions NAME@?+ | | | | Goto labels NAME$?* | | --------------------------------------------------------- | | NAME, NAM MC identifier, 1 to n characters, upper case | | [external identifiers should be limited to a | | length of seven significant characters]. | | | | # The local label number | | | | * The function number (within the module) | | | | + The compound block number (within the module) | |_____________________________________________________________| MC generates labels in this fashion so that static variables, external variables, and labels will not conflict with each other. Thus, there can be an external variable named x, a static named x in two different modules, a static named x in two different functions in the same module, and a (goto) label named x, all within the same program, with no conflicts. A dollar sign, '$', is appended to external or static labels which are three characters long or less. This prevents possible conflicts with register names and logical operators in your assembler. Local labels are used to implement strings, double precision constants, conditional statements and operators, and loops. They are assigned numbers starting with 1 and incremented by 1. Runtime variable storage format Characters occupy eight bits and are stored in single 8-bit bytes; they are considered unsigned. Integers and short integers occupy sixteen bits and are stored in two 8-bit bytes. The leftmost bit (which is the sign bit of signed integers) is the most significant; the rightmost bit the least significant. Integers are stored in memory with the low-order byte occupying the lower machine address. `Advanced Topics - Assembly Language` 5 - 24 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Long integers occupy thirty-two bits and are stored in four 8-bit bytes. The leftmost bit, bit 31 (which is the sign bit of signed integers), is the most significant; the rightmost bit the least significant. Long integers are stored in memory with the lowest-order byte occupying the lower machine address, the next higher-order byte occupying the next higher machine address, and so forth. Single precision floating point numbers occupy thirty-two bits and are stored in four 8-bit bytes, a three-byte fractional part in bit positions 0-23 and a one-byte exponent in bit positions 24-31. The leftmost fraction bit (which is the sign bit of the number) is the most significant; the rightmost bit the least significant. Floats are stored in memory with the lowest-order fraction byte occupying the lower machine address, the middle- order fraction byte occupying the next higher machine address, the highest- order fraction byte occupying the next higher machine address, and the exponent occupying the highest address. Double precision floating point numbers occupy sixty-four bits and are stored in eight 8-bit bytes, a seven-byte fractional part in bit positions 0-55 and a one-byte exponent in bit positions 56-63. The leftmost fraction bit (which is the sign bit of the number) is the most significant; the rightmost bit the least significant. Double precision floating point/ numbers are stored in memory with the lowest-order fraction byte occupying the lower machine address, the next higher fraction byte occupying the next higher machine address, etc., and the exponent occupying the highest address. The exponent of a floating point number is stored in "excess 128" nota- tion. Using the syntax "**" to indicate "raise to the power", this means that an exponent of zero (2**0 = 1) is represented by 128D (80H); positive expo- nents are denoted by values of greater than 128, and negative exponents by values of less than 128. Thus, by subtracting 128 from the value, the true exponent is obtained. The fractional part of a floating point number is always in BINARY normalized form, which means that the values lie within the range: 2**-1 <= X < 2**0 A little simple arithmetic will show that this range, base 10, is (.5<=X<1). All this means is that there will always be a one (1) immediately to the right of the binary point when the binary normalized mantissa is shown in its binary form. Since there will always be a one bit in this high-order bit of the normalized fraction, it is not necessary that it be kept. In fact, the bit is dropped entirely and the position in the normalized fraction is used to store the SIGN of the entire number; a one indicating a negative number and a zero indicating a positive number. Register Utilization All registers are available for use by an assembly language function with the exception of the index registers, IX and IY. If you want to use the index registers, they must be saved on entry to your function and restored on exit. The stack pointer must be returned in the same condition as it was upon entry. `Advanced Topics - Assembly Language` 5 - 25 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` For math operations, the following CPU registers are used, in general, to contain the various variable types: Type primary secondary notes ------ ------- --------- --------------------------------- char L* E* * high-order byte zeroed int HL DE long BCDE stack float BCDE stack double (HL)* stack * 8 bytes moved to memory storage Argument passing C passes arguments on the machine stack. Each argument is pushed onto the stack according to its memory storage format [characters take two bytes of stack space of which the higher order byte is ignored]. Arguments are pushed in an order opposite of the order they are specified in the function call. Here is the assembly language which C generates to perform a function call (it is assumed that "x", "a", "b", and "c" are each static integers and the function returns an integer; we will ignore the use of macros): ; x=func(a,b,c); LD HL,(C$) PUSH HL LD HL,(B$) PUSH HL LD HL,(A$) PUSH HL CALL FUNC POP AF POP AF POP AF LD (X$),HL This process generates the following appearance on the Z-80 machine stack: (SP+6) ==> (SP+4) ==> (SP+2) ==> (SP+0) ==> return address That is how the arguments appear to the called function when first entered. There are several methods which can be used within the called function to obtain the arguments. The simplest method is to POP each argument off the stack. This is not suitable for large numbers of arguments, but most effi- cient for 3 operands or less. Using the example above, the arguments could be retrieved as follows: `Advanced Topics - Assembly Language` 5 - 26 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` FUNC POP AF ;return address saved POP BC ;argument in BC POP DE ;argument in DE POP HL ;argument in HL PUSH HL ;restore argument PUSH DE ; " " PUSH BC ; " " PUSH AF ;stack is same as at entry Note that the stack is returned to its original condition. It is always important to keep track of the stack pointer. However, the contents of the stack, i.e., the arguments, are "owned" by the called function and can be used like any local variable. A better method to use when dealing with large numbers of arguments is shown below: LD HL,2 ;offset to ADD HL,SP ;HL = address of CALL @GINT ;get contents of @GINT is a run-time library function which gets the integer pointed to by HL into HL. Another method is to utilize the Z-80 index registers. The stack pointer must be placed into the index register first, then index offset values can be used to get and store the arguments: PUSH IX ;Must save register IX LD IX,0 ADD IX,SP ;Get SP into IX LD L,(IX+2+2) ;Get LSbyte of a LD H,(IX+3+2) ;Get MSbyte of a POP IX ;Restore IX If an argument is intended to be a character variable, only the least significant byte (LSbyte) is needed, so a single indexed load is used. Returning a value from a function MC programs use the primary register associated with the function type in order to return the function's value (see "register utilization" above). For instance, a short int should use the HL register pair for a 16-bit accumulator. Any short int value to be returned by a called function must be placed in HL before returning to the calling function. Take care that a full 16-bit value is returned. If a character or 8-bit value is being returned, then H should be loaded with zero. If a TRUE or FALSE indication is to be returned, HL should be set to 1 or 0, accordingly. `Advanced Topics - Assembly Language` 5 - 27 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` This page intentionally left blank `Advanced Topics` 5 - 28 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` Preprocessor errors - Warning The following messages may occur during the preprocessor phase of com- pilation and are only warnings; processing continues. Preprocessor warnings are unnumbered messages. "Conditionals nested too deeply" The maximum conditional nest depth is 256. How you reached that limit is beyond imagination. "#else without #if" This obviously occurs when a "#else" is detected without any previously corresponding "#if". "#endif without #if" This is emitted when a "#endif" is detected without a previously cor- responding "#if". "Extra macro parameters, ignored" A parameterized macro was invoked with more arguments than when the macro was defined. Double check your argument list. "Illegal preprocessor directive" The input stream provided a "#something" when "something" was not one of the legal directives. "Multiple #else's" Only one #else per #if is allowed. "Redefining " This informs you that a previously defined macro is being redefined. It is not an error. "Undefining nonexistent macro" This informs you that a macro is being undefined which had not previ- ously been defined. It is not an error. "Unterminated conditional(s)" The end of the input file stream was reached while one or more "#if" conditionals was left unclosed by a corresponding "#endif". "Unterminated input line" The end of the input file stream was reached with a missing newline at the EOF. `Appendix - Error Messages` A - 1 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` "Unterminated string or char constant" A string or character constant was being read from the input stream and the end of the line (EOL) was reached without the closing corresponding double quote or single quote. Preprocessor errors - Fatal The following errors which may occur during the preprocessor phase of compilation are considered "fatal errors"; they result in the termination of the process. "-? argument too long" A command line -d or -u option is longer than 64 characters. "Duplicate macro arguments" A parameterized macro definition has two dummy arguments with the same name. "Illegal constant expression" The operand field of a "#if" or "#option" must be a valid constant expression. "Illegal floating point constant" The floating point constant does not follow the K&R rules. "Illegal hex constant" A hexadecimal constant is improperly formed according to the rules for such constants as noted in K&R. "Illegal macro definition" A parameterized macro dummy argument list was improperly formed. "Include filespec missing" A "#include" directive was encountered which had no file specification in the operand field. "Includes nested too deeply" The "#include" statement would have nested too deeply, if not ignored. Up to eight (8) nesting levels are available in MC. `Appendix - Error Messages` A - 2 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` "Invalid command line option" One of the options specified in the command line was not a valid MC option. "Invalid #line" A "#line" preprocessor statement was improperly formed. "Macro calls nested too deeply" The maximum macro nest depth is 20 which has been exceeded. You will have to redesign your use of macros. "Missing ')'" The operand field of a "#if" or "#option" used an open parenthesis in a constant expression but the corresponding closing parenthesis was omitted. "Missing ':'" The conditional operator "?:" was used in the constant expression oper- and of a "#if" or "#option" directive but the ":" was omitted. "Missing macro parameters" A parameterized macro was invoked with fewer formal arguments than when the macro was defined. Double check your argument list. "Missing or illegal identifier" The syntax required an identifer, but the input text did not conform to C's rules for identifiers. "Must be short int or char constant" #option requires a short integer or character constant if a constant expression is present. "No input file given" No input files were specified on the command line which invoked MCP. "Out of memory" No more memory space is available. Either decrease the amount of memory reserved in high memory or split the module being compiled into smaller mod- ules with fewer external variables. You may also consider decreasing the amount of modules in high memory (filters, KSM, SYSRES'ed overlays, etc.) and try to execute MCP again. "Too many macro arguments" A parameterized macro was defined with more dummy arguments than allowed (128). Double check your argument list. `Appendix - Error Messages` A - 3 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` "Unterminated macro call" A macro call was missing the closing parenthesis. Compiler errors - fatal The following messages may occur during the compiler phase. The errors attributing to the emittance of such messages are considered fatal errors. These messages are unnumbered. Compilation aborted A fatal error was detected which prevented the compiler from continuing the process of compilation. "No input filespec" No input file was specified on the command line which invoked MC. "Out of memory" No more memory space is available. Either decrease the amount of memory reserved in high memory or split the module being compiled into smaller mod- ules with fewer external variables. You may also consider decreasing the amount of modules in high memory (filters, KSM, SYSRES'ed overlays, etc.) and try to execute MC again. "Too many input files" Only one input file may be passed on the command line to the compiler. "Unrecognizable option" This results from a bad command line option. Compiler errors - warning The following messages are warnings and do not normally result in an immedate abort of the compiler's processing. The messages fall into broad classifications. These messages are emitted along with the error number shown. `Appendix - Error Messages` A - 4 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` General syntax errors (10-19) 10 - "Missing ':'" A "?" operator was found without a matching ":" operator. This may also arise from an omission of the colon from a structure/union bit field decla- ration. 11 - "Missing '('" An opening parenthesis was omitted from where it was required. 12 - "Missing ')'" The syntax of the statement being parsed required a closing parenthesis which was omitted. 13 - "Missing ']'" The field specifying the subscript of an array object was not terminated with the closing square bracket. 14 - "Missing '{'" The opening brace required to designate a compund block was omitted. 15 - "Missing '}'" The end of the input stream was encountered without a closing brace for the current function being found. 16 - "Missing ';'" No semicolon was found at the end of a statement. The ';' character is the statement terminator, and must be placed at the end of a simple state- ment. It's also required in a "for" statement [i.e. for ( ; ; )]. 17 - "Missing ','" The context of the input required a comma, but none was found. Constant expression errors (20-29) 20 - "Illegal constant expression" A constant expression did not follow the K&R rules. `Appendix - Error Messages` A - 5 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` 21 - "Must be short int or char constant" An object of case, array dimension, or initializer requires a short integer or character constant. Declaration errors (30-49) 30 - "Illegal declaration or typename" A catch-all - Some sort of bad syntax in a declaration or cast or sizeof, not otherwise mentioned. 31 - "Declaration too complex" More than 16 levels of "array of", "pointer to", or "function returning" occurred in a declaration. 32 - "Struct/union includes self" A structure/union may not include an instance of itself as a member; however, a pointer to an instance of itself may be included as a member. 33 - "Cannot return struct/union" It is impossible for a function to return a structure or union; however, a function can return a pointer to a structure or union. 34 - "Function not declared" The context of the input demanded that a function be declared, i.e., the input did not match anything which could be a compiler directive or a vari- able declaration, so it was assumed that a function was being declared. 35 - "Zero size illegal" An array dimension is zero or missing where required, or sizeof returned zero when invoked. 36 - "Redefinition" The object being declared has already been defined in the module. 37 - "Argument list illegal" A function argument list was found in a function FORWARD DECLARATION. Only allowed in a function DEFINITION. `Appendix - Error Messages` A - 6 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` 38 - "Illegal argument name" An argument name in the argument list of a function definition is not a valid C identifier. 39 - "Unmatched argument" The function argument being declared did not match any of those in the argument list for the function. Initialization errors (50-59) 50 - "Illegal initializer" This is a catch-all emitted when something wrong is detected with the syntax of an initializer. 51 - "Undefined" The object being referenced in an initializer has not been defined. You may wish to check the spelling. 52 - "Must be static or external" An initializer using the address of an automatic or register variable is illegal. Statement errors (60-69) 60 - "Compound statement required" The switch-case statement must have a compound statement as its sub- statement. The body of a function must also be a compound statement (i.e. one enclosed in curly braces). 61 - "Declaration follows executable statement" All declarations in a block must precede the first executable statement in that block. Resequence your statements. `Appendix - Error Messages` A - 7 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` 62 - "No while after do" A "do" statement was compiled, but no "while" statement followed it. 63 - "Void function return" A function declared as void contains a return statement with an expres- sion following. 64 - "Bad label" The label specified in a "goto" statement or as a statement label was not a valid C identifier. 65 - "Extra default" The body of a "switch" statement included more than one default sub- statement. Expression errors (70-99) 70 - "Illegal expression" The input could not be recognized as an expression when the context of the program required an expression. 71 - "Illegal floating point operation" A float or double expression is using an operator that's not allowed. See the language specifications in Chapter 2 for valid floating point oper- ators. 72 - "Illegal pointer operation" An operation was attempted on a pointer other than that documented on page 2-12. 73 - "Illegal address" The "&" (address of) operator was used with an expression which was not an object in memory. 74 - "Not a pointer expression" The indirection operator, "*", was used with an expression which does not result in the address of an object in memory. `Appendix - Error Messages` A - 8 `The MISOSYS C Language Compiler` `Copyright (c) 1985 MISOSYS, Inc., All rights reserved` 75 - "Using void result" An expression is attempting to use the non-existent return value of a function which was defined to be of type void. 76 - "Function name illegal" The name of a function was used improperly. Check for misspelling or missing variable definition. 77 - "Must be lvalue" The expression being processed specifies that a value be placed into an object, but no object which could be stored into was found. This occurs in assignments, "++", and "--". Usually it's the result of a spelling error. 78 - "Must be struct/union and not array" The left side of a "." or "->" requires this. 79 - "Unknown struct/union" The structure/union object being declared or referenced has not had a template defined for it. 80 - "Must be struct/union pointer" The designated operation requires a pointer, not the object itself. 81 - "Member name required" The operand on the right hand side of a "." or "->" must be a member of the structure/union on the left hand side. 82 - "No such member" The referenced member of a structure/union has not been defined in the structure/union template. 83 - "Must be array or pointer" Square brackets "[]" were applied to an object which was neither a pointer nor an array. 84 - "Illegal function call" A function call is being attempted, but the object being called is not a function name or dereferenced function pointer. `Appendix - Error Messages` A - 9