Introduction to the SAS/C® Library

Commonly Used Functions

This book describes the most commonly used functions in the SAS/C library. Chapter 2, "Function Categories," itemizes the functions by the following category: Functions are listed alphabetically in Chapter 6, "Function Descriptions."

Special Features

The following special features of the SAS/C library are documented in SAS/C Library Reference, Volume 2 :

Additionally, SAS/C Library Reference, Volume 2 documents the SAS/C socket library for TCP/IP and SAS/C POSIX support.

Compatibility with Standards

Most functions in the SAS/C library are compatible with industry-recognized C library standards, including

ISO/ANSI C Standards

The SAS/C library is fully compliant with the 1990 ISO/ANSI C standard. Implementation-defined behavior for the ISO/ANSI library is described in Chapter 2, "Language Definition" in SAS/C Compiler and Library User's Guide, Fourth Edition .

Traditional UNIX Support

The SAS/C library supports a number of functions defined by traditional (pre-POSIX) UNIX systems. In some cases, these functions are limited to use with the OpenEdition MVS operating system, an International Business Machines Corporation Product. However, in many cases, these functions have been defined so that they are meaningful in native MVS and CMS environments. For instance, although the stat and link functions are limited to use with OpenEdition files, other functions such as open, read, write, and access can be used with most MVS and CMS file types.

Unlike the ISO/ANSI and POSIX libraries, the traditional UNIX library is not defined as a formal standard. Rather, the traditional UNIX library is informally defined by consensus with a number of different UNIX implementations, based on both System V and BSD.

Although SAS/C does not and cannot support every function defined by every historical UNIX variant, the library does attempt to offer support for a large subset of the core UNIX functionality, especially functions frequently used in portable programs. Note, however, that some core functions, such as fork and kill, cannot be implemented under MVS or CMS by an application-level library such as the SAS/C library without operating system support (such as OpenEdition MVS).

POSIX Standards

In addition to the functionality provided in earlier releases of SAS/C, Release 6.00 supports OpenEdition MVS. OpenEdition comprises three products:

SAS/C, Release 6.00 directly uses the MVS support for OpenEdition, and you can use it with the Shell and Utilities product. The dbx debugger does not support SAS/C programs, but you can use the traditional SAS/C debugger under the shell instead of using dbx.

Using the underlying functionality of the MVS support for OpenEdition, SAS/C, Release 6.00 enables you to

To support these features, the Institute made some changes to the SAS/C compiler and debugger, but most changes are localized to the resident and transient libraries. Compile-time header files are also significantly changed.

The POSIX 1003.1 standard is an ISO standard that specifies operating system functionality in a C language interface. With OpenEdition, the SAS/C library implements this interface under MVS. OpenEdition and SAS/C also implement portions of the 1003.1a draft standard and related extensions. POSIX 1003.1 is based on common elements of a number of UNIX operating systems.

The SAS/C POSIX implementation is documented in Part 3, "SAS/C POSIX Support," in SAS/C Library Reference, Volume 2 .

Rules for Using Different Releases of the Compiler and Library

Here are the rules for compiling, linking, and executing programs with different releases of the compiler and library:

Table 1.1 shows the likely result of using different releases of the compiler and the resident and transient libraries to compile and link programs. If you are unsure which version of the library you are using, you can use the =version run-time option, which displays the library version numbers.

Note: Combining more than three versions of the compiler and resident and transient libraries becomes very complicated and is not documented here. In Table 1.1 where a row contains two entries of "older," they refer to the same older version.

Table 1.1 Likely Results of Mixing Releases of the Compiler and Libraries


    Program   Transient    Resident     Compiler     Likely
              Library      Library      Release      Result:
              Release      Release                   Will
                                                     Program
                                                     Run?
 

   1          current      current      current      Yes

   2          current      current      previous     Yes

   3          current      current      older        Yes

   4          current      previous     current      No

   5          current      previous     previous     Yes

   6          current      previous     older        Yes

   7          current      older        current      No

   8          current      older        previous     No

   9          current      older        older        Yes

   10         previous     current      current      No

   11         previous     current      previous     No

   12         previous     current      older        No

   13         previous     previous     current      No

   14         previous     previous     previous     Yes

   15         previous     previous     older        Yes

   16         previous     older        current      No

   17         previous     older        previous     No

   18         previous     older        older        Yes

   19         older        current      current      No

   20         older        current      previous     No

   21         older        current      older        No

   22         older        previous     current      No

   23         older        previous     previous     No

   24         older        previous     older        No

   25         older        older        current      No

   26         older        older        previous     No

   27         older        older        older        Yes

 

Library Header Files

The functions provided by the library are associated with header files. Each header file contains the function prototype and any necessary types and macros associated with the functions. In some cases, the correct use of a function may require more than one header file.

For maximum portability and efficiency, always include the header files for all of the library functions called in a compilation. This practice has two benefits:

Header File Organization

The SAS/C library defines a strict separation of functions into three parts:

Functions defined by the ISO/ANSI standard are declared in the header file mandated by the standard. For example, the fopen function is declared in <stdio.h>. The names of the standard header files are

Functions defined by another standard are declared in the header file mandated by the standard. If that file is also an ISO/ANSI C standard header file, you must use a feature test macro to make the declaration visible. Feature test macros are described in more detail in the next section.

Functions which are not defined by the ISO/ANSI Standard but which are related to standard functions are declared in separate header files. These header filenames are similar to the Standard names but have the prefix lc. For example, the function afopen is declared in <lcio.h>. The names of these header files are

This separation of functions is intended as an aid in writing portable programs. Only those functions declared in the standard header files are completely portable.

If you include the lc- header file, you do not need to include the standard header file. In all cases, the lc- prefixed header contains a #include statement for the standard header file. For example, the header file <lcstring.h> contains the statement #include <string.h>. (It is not an error to explicitly include both files.) The SAS/C library contains many nonstandard functions and header files that are not associated with standard features. For details on nonstandard functions and header files that are not associated with standard features, see SAS/C Library Reference, Volume 2 .

Feature Test Macros

Feature test macros are defined by various IEEE POSIX standards to enable you to specify the standards and language features that you wish to use. SAS/C uses feature test macros in the following way: SAS/C supports the following feature test macros. To enable a feature, you must define the macro before including any header file, either by using a #define statement or by using the define compiler option.
_SASC_POSIX_SOURCE
If this macro is defined as any value, symbols defined by a supported POSIX.1 standard will be made visible in ISO/ANSI standard header files. _SASC_POSIX_SOURCE has no effect on non-ISO/ANSI header files.
_POSIX_SOURCE
If this macro is defined as any value, symbols defined by the POSIX.1 standard will be made visible in ISO/ANSI standard header files. Also, declarations of any symbols that are not specified as allowable in POSIX.1-header files in the POSIX.1 standard will be suppressed. _POSIX_SOURCE should be defined only for programs which are intended to be POSIX-conforming and which do not use any non-ISO/ANSI or non-POSIX library features.
_POSIX1_SOURCE
If this macro is defined as 1, the effect is the same as defining _POSIX_SOURCE. If this macro is defined as 2, symbols sanctioned by the POSIX.1a draft standard related to features implemented by OpenEdition MVS will also be made visible. Like _POSIX_SOURCE, _POSIX1_SOURCE should not be defined in any program that uses non-ISO/ANSI non-POSIX features.
_POSIX_C_SOURCE
If this macro is defined as 2, it has the effect of defining _POSIX_SOURCE, plus making visible symbols sanctioned by the POSIX.2 draft standard related to features implemented by SAS/C. If _POSIX_C_SOURCE is defined to any other value, it has the same effect as defining _POSIX_SOURCE. Like _POSIX_SOURCE, _POSIX_C_SOURCE should not be defined in any program that uses non-ISO/ANSI non-POSIX features.
If you use the POSIX compiler option, the feature test macro _SASC_POSIX_SOURCE is automatically defined. This does not ensure that your program is POSIX compliant; it only makes visible POSIX symbols in ISO/ANSI standard header files.

The errno Variable

The external int variable errno contains the number of the most recent error or warning condition detected by the run-time library. To use this value, include the header file <errno.h>.

If no error or warning condition is detected, the value of errno is 0. After program execution starts, errno is never reset to 0 by the library. Programs that use errno for information about unusual conditions must set it to 0 before calling a library routine that may detect such a condition.

The <errno.h> file contains declarations of the errno variable and definitions of symbolic names for the values that can be assigned. These names rather than numeric values should be used for errno.

SAS/C defines a number of general-use errno names. There are also many errno names associated with specific sublibraries, notably the SAS/C socket library and the SAS/C POSIX support. Socket errno names are documented in Chapter 15, "The BSD UNIX Socket Library," in SAS/C Library Reference, Volume 2 , and errno names related to OpenEdition are documented in Chapter 19, "Introduction to POSIX," in SAS/C Library Reference, Volume 2 . For a complete listing of all errno values, see SAS/C Compiler and Library Quick Reference Guide .

The following list defines the error names and meanings that are for general use, and thus not associated with a specialized API, such as sockets:

EARG
undefined function argument value
EBADF
file or socket not open or suitable (synonym for ENOTOPEN)
ECONV
data conversion failure
ECORRUPT
file is in a corrupt or unreadable state
EDEVICE
physical device error
EDOM
math function domain error
EDUPKEY
attempt to add record with duplicate key
EEXIST
file already exists
EFATTR
file attribute conflict
EFFORM
file format error
EFORBID
function execution prevented by run-time options
EILSEQ
error in multi-byte character sequence (reserved for future use)
EINTR
function failed due to interruption by signal
EINUSE
file to be opened was already in use
EINVAL
invalid argument (synonym for EARG)
EIO
physical I/O error (synonym for EDEVICE)
ELIBERR
run-time system internal error
ELIMIT
internal limit exceeded
EMFILE
too many open files (synonym for ELIMIT)
ENFILE
too many open HFS files in system
ENFOUND
file not found
ENOENT
file or directory not found (synonym for ENFOUND)
ENOMEM
insufficient memory
ENOSPC
no space in file
ENOSYS
function not implemented by system
ENOTOPEN
synonym for EBADF
EPREV
previous error not cleared
ERANGE
math function range error
ESYS
operating system interface failure
EUNSUPP
unsupported I/O operation
EUSAGE
incorrect function usage.

The variable errno is implemented as a macro. If you use errno without including <errno.h>, the correct data may not be accessed.

The only portable values for errno are EDOM and ERANGE. The following example illustrates the use of errno:

 #include <errno.h>
 #include <stdio.h>

 FILE *f;
 char *filename;
 if (!(f = fopen(filename, "r"))) {
       /* See if any file can be opened. */
    if (errno == ELIMIT) {
       printf("Too many open files\n");
       return(EOF);
    }
    else {
       printf("%s could not be opened, enter new filename\n",
              filename);
       getfname(filename);
    }
 }
 

More Exact Error Information: _msgno Variable

The header file <lcdef.h> contains the declaration of a nonstandard external variable, _msgno. This variable contains the message number of the last SAS/C library diagnostic. For example, if the last message ID were LSCX503, _msgno would contain 503.

_msgno may provide more information about a failure than errno. For instance, trying to read a file that has not been created sets errno to ENFOUND, but you can use _msgno to distinguish the cases of an empty sequential file (_msgno = 503) and a missing PDS member (_msgno = 504). _msgno is not portable, so programs that must be portable should use only errno.

_msgno is implemented as a macro, so you should not use the name for any other purpose.

System Macro Information

The SAS/C System Macro Information (SYSMI) facility provides a way for a program to determine accurate information about a library failure caused by an error return code from a system macro or service. The information available includes the name of the service and the numeric codes associated with the failure.

When the library calls an operating system service (including an OpenEdition system call) that fails, information about the failure is saved in a library structure. Macros are defined in <lcdef.h> to enable user code to determine the service that failed and the resulting failure codes. Only the most recent failure information is saved; information is not saved for successful services.

The following macros are defined:

__sysmi_macname
expands to a null-terminated string naming the macro or service that failed. For OpenEdition system calls, this is the BPX name of the failing service.
__sysmi_rc
is the return code of the failing service. For OpenEdition system calls, this is the numeric value returned by OpenEdition before library translation into an errno value.
__sysmi_reason
is the reason code of the failing service (or 0 if no reason code was returned). For OpenEdition system calls, you can find the meaning of the last two bytes of the reason code in the IBM publication Assembler Callable Services for OpenEdition MVS.
__sysmi_info
is the information code for the failing service (or 0 if this code is not applicable).

You can use the macro __sysmi_clear to clear previously stored system macro information. You may wish to call __sysmi_clear before calling a routine that might store SYSMI information to ensure that any such information relates to the most recently called function.

Definitions: <lcdef.h>

Several nonstandard macros are defined in <lcdef.h>. The following pages describe these macros, offsetof, isunresolved, isnotconst, isnumconst, and isstrconst.

offsetof - Get the Byte Offset of a Structure Component

SYNOPSIS

 #include <stddef.h>

    /* macro */
 size_t offsetof(type, element)
 

DESCRIPTION

The offsetof macro provides the decimal byte offset of a component within a structure as a size_t constant. This constant is generated at compile time. Padding for alignment, if any, is included. The operands of offsetof are a structure type (type) and a component of the structure specification (element). The component specification does not include the structure type or the selection operators . or ->.

RETURN VALUE

offsetof returns the byte offset of element.

EXAMPLES

As shown in these examples, you should write the member specification as it would be written to access the value of a structure member, except that there is no leading . or -> selection operator.

Example 1.1

 #include <stddef.h>

 struct AAA {    /* Define structure AAA. */
    double ddd;
    char ccc;
    int bbb;
    };
 long x;
    /* x is the byte offset of component bbb in struct AAA. */
 x = offsetof(struct AAA, bbb);
 
Example 1.2 shows a structure, data, with an inner structure base.

Example 1.2

 #include <stddef.h>

 struct data {        /* Define struct data.      */
    int id;
    int *elem;
    char *name;
    struct {          /* Define struct type base. */
       double proj;
       } base;
    };
 
    long ofs;
       /* ofs is the byte offset of base.proj.     */
    ofs = offsetof(struct data, base.proj);
 
In Example 1.3, complex is defined via a typedef statement to be a structure type. The component specification inner.d[5] specifies an array element within an inner structure. The variable y is set to the offset of the sixth array element in the inner structure (decimal 56).

Example 1.3

 #include <stddef.h>

 typedef struct {   /* Define struct type complex. */
    struct XXX *xptr, *xptr2;
    struct {         /* Define struct type inner.  */
       int count, count2;
       double d[10];
       } inner;
    struct XXX *xptr3;
    } complex;
       /* y is the byte offset of inner.d[5].       */
    long y;
    y = offsetof(complex, inner.d[5]);
 

isunresolved - Test Whether an External Symbol is Resolved

SYNOPSIS

 #include <lcdef.h>

 int isunresolved(name);
 

DESCRIPTION

This macro tests the name (which should be the name of a variable declared as __weak) to determine whether the symbol was resolved by the linkage editor.

RETURN VALUE

isunresolved returns 0 if the symbol is resolved, or a nonzero value if it is not resolved.

EXAMPLE

  /* Test whether the function db_open() is present */
  /* in the load  module.  If it is, call it.       */

     /* optional database open function */
  extern int __weak db_open(char *);

  if (!isunresolved(db_open))
     db_open("DBNAME");

 

SEE ALSO

Chapter 2, "Language Definition," in SAS/C Compiler and Library User's Guide, Fourth Edition

isnotconst - Test for Nonconstant
isnumconst - Test for Numeric Constant
isstrconst - Test for String Literal

SYNOPSIS

 #include <lcdef.h>
 int isnotconst(expression);
 int isnumconst(expression);
 int isstrconst(expression);
 

DESCRIPTION

These macros examine expression and return a compile-time constant. If expression is the appropriate type of constant, a nonzero constant is returned; otherwise, 0 is returned. The type tested for is numeric for isnumconst, string literal for isstrconst, and nonconstant for isnotconst. The expression constant can have any type.

expression is never evaluated, and these macros always yield a constant, regardless of the type of expression.

The isnotcons, isnumconst, and isstrconst macros are used primarily to control the generation of code by in-line functions. Because they produce compile-time constants, the macros can be tested at compile time, enabling the compiler to eliminate sections of code that can never be executed.

EXAMPLES

Below are several examples using these nonstandard macros:

Example 1.4

 if (isnotconst(argv[]))                 /* true  */
 if (isnumconst(100))                    /* true  */
 if (isstrconst("XYZ"))                  /* true  */
 if (isstrconst(c == 0 ? "A" : "B")      /* false */
 

Example 1.5

 #define MAXLEN 1024

 if (isnumconst(MAXLEN) && 500 < MAXLEN) /* true  */
 

Example 1.6

This example defines the function smemcpy (meaning short memcpy) that prevents the expansion of the built-in memcpy function unless the length argument is a constant integer less than or equal to 256. If the length argument is greater than 256 or is not a constant integer, a call to the true memcpy function is generated.

The if condition is a constant expression and is evaluated at compile time. The compiler generates code either for the then branch or the else branch, depending on the result of the test. Under no conditions is code for both branches generated.

 #include <lcdef.h>
 #include <string.h>

 #define smemcpy(d, s, len)
         inline_memcpy(d, s, len, isnumconst(len))
 __inline
 void *inline_memcpy(void *d, const void *s,
                     size_t len, int cnst)
 {
    if (cnst && len < 257)
       memcpy(d, s, len);
    else
       (memcpy)(d, s, len);
    return d;
 }
 

Implementation of Functions

Built-in Functions and Macros

Many of the functions in the library are implemented as built-in functions. A built-in function is a function for which the compiler generates the required machine instructions directly in the compiled code instead of making a call to a separately compiled routine. True functions are compiled separately and must be linked with the program before they can be executed. By eliminating the overhead of parameter list creation and branching, a built-in function is always more efficient than a call to a true function. Generally, built-in functions can be implemented by a relatively short sequence of machine instructions. These afford the greatest increase in efficiency. The abs function is a good example:
 #include <math.h>
 int gt5(register int i){
  return (i < -5) ? i + 5 : abs(i);
  }
 
Given this C function, the compiler generates a single IBM 370 machine instruction called Load Positive Register (LPR) to get the absolute value of i. However, calling and executing the true abs function in this example requires the execution of 20 machine instructions.

The compiler and library implement built-in functions by defining a macro in the header file that prefixes the string __builtin_ to the function name. For example, the strcpy function is declared as follows:

 #define strcpy(x, y) __builtin_strcpy(x, y)
 
The compiler recognizes the prefix and generates the appropriate machine instructions. If you do not include the header file, the compiler does not recognize the function as a built-in function and generates a call for the function.

For some built-in functions, the compiler may generate a call to the true function as part of the code sequence. This occurs when the value of one or more of the function arguments cannot be determined at compile time and may fall outside of the range of values that the in-line code can handle. At execution time, the arguments are evaluated, and either the in-line code is executed or the true function is called.

If a built-in function is called with invalid arguments or an invalid number of arguments, a call to the true function is generated.

Following is a list of all SAS/C built-in functions:


   _bbwd     abs       memcpyp    strncmp

   _bfwd     ceil      memscan    strscan

   _branch   fabs      memscntb   strscntb

   _cc       floor     memset     strxlt

   _cms202   fmax      memxlt     tolower

   _code     fmin      min        toupper

   _diag     getc      modf

   _label    labs      putc

   _ldexp    max       sigchk

   _ldregs   memcmp    strcmp

   _ossvc    memcmpp   strcpy

   _stregs   memcpy    strlen

 
Following is a list of all SAS/C functions implemented as macros, other than built-in functions:

   ABEND *           TPUT_USERID *   getchar        pause

   CHAP *            TTIMER *        htonl          pdset *

   CMSSTOR_OBT *+    WAIT1 *         htons          pdval *

   CMSSTOR_REL *+    WAITM *         isalnum        pfree

   DEQ *             WAITT *         isalpha        putchar

   DETACH *          WRTERM *        iscics         setbuf

   DMSFREE *         appcconn *+     iscntrl        shvdrop *

   DMSFREE_V *       appcrecv *+     iscsym         shvfetch *

   DMSFRET *         appcscfd *+     iscsymf        shvfirst *

   ENQ *             appcscnf *+     isdigit        shvnext *

   ESTAE *           appcsdta *+     isebcdic       shvset *

   ESTAE_CANCEL *    appcserr *+     isgraph        sigsetjmp *

   FREEMAIN *        appcsevr *+     islower        strcspn

   GETLONG *         appcsreq *+     isnotconst *   strspn

   GETMAIN_C *       assert *        isnumconst *   toebcdic

   GETMAIN_V *       atof            isprint        typlin *

   GETMAIN_U *       atoi            ispunct        unloadd

   GETSHORT *        cfgetispeed     isspace        va_arg *

   POST *            cfgetospeed     isstrconst *   va_end

   PUTLONG *         cmspush *       isunresolved * va_start *

   PUTSHORT *        cmsqueue *      isupper        waitrd *+

   RDTERM *          difftime        isxdigit       xedpoint

   STATUS *          e_SVC202        labs           xedread

   STIMER *          execdrop *      localtime      xedstate

   STIMERM_CANCEL *+ execfetch *     memchr         xedwrite

   STIMERM_SET *     execset *       ntohl

   STIMERM_TEST *    exit            ntohs

   SVC202            fattr +         offsetof *

   TGET *            ffixed +        onjmp *

   TPUT *            fnm +           onjmpout *

   TPUT_ASID *       fterm +         palloc

 
* = may not be undefined.
+ = evaluates some arguments more than once.


Copyright (c) 1998 SAS Institute Inc. Cary, NC, USA. All rights reserved.