www.sas.com > Service and Support > Technical Support
 
Technical Support SAS - The power to know(tm)
  TS Home | Intro to Services | News and Info | Contact TS | Site Map | FAQ | Feedback


/*-------------------------------------------------------------------+
|                Copyright (c) 1996, SAS Institute Inc.              |
|                  Unpublished - All Rights Reserved                 |
|                      S A S / C   S A M P L E                       |
|                                                                    |
|         NAME: WDSAMPLE                                             |
|     LANGUAGE: C                                                    |
|      PURPOSE: To demonstrate the use of the SAS/C Windowing        |
|               interface functions with the use of the SAS/C FSSL.  |
|               See SAS/C Full Screen Support Library User's Guide,  |
|               Second Edition, Chapters 5, 6, and 7.                |
| INSTALLATION: Before compiling, you will need to modify the        |
|               filename value in the browse_init function.          |
|               To quickly find it, search for the string "fopen".   |
| SYSTEM NOTES: This routine will run on either CMS or TSO           |
|               Proper execution will require that the SAS/C         |
|               transient library, release 5.00H or higher, be       |
|               available at runtime.                                |
| INPUT/OUTPUT: A series of windows including PF values, browsing    |
|               the source code for this very program, and playing   |
|               a simple number guessing game.                       |
|   MVS -                                                            |
| COMPILE/LINK: SUBMIT prefix.SAMPLE.AUX(WDSAMPLE)                   |
|               where "prefix" is the installation defined high-level|
|               qualifier for the SAS/C product.                     |
|      EXECUTE: execute under TSO, see below                         |
|   TSO -                                                            |
|      COMPILE: LC370 CLIST                                          |
|         LINK: CLK370 CLIST                                         |
|      EXECUTE: CALL your.load.lib(WDSAMPLE)                         |
|   CMS -                                                            |
|      COMPILE: GLOBAL MACLIB LC370 L$FSSL                           |
|               LC370 WDSAMPLE                                       |
|         LINK: GLOBAL TXTLIB LC370BAS LC370STD L$FSSL               |
|               CLINK WDSAMPLE (GENMOD                               |
|      EXECUTE: WDSAMPLE                                             |
|                                                                    |
+-------------------------------------------------------------------*/
#eject
/* Some useful macro's to make field manipulation understandable */
#define GAME_RESULT_LINE 6
#define GAME_RESULT_GUESSES_LEFT 10
#define GAME_RESULT_LAST_GUESS 24
#define GAME_RESULT_FIELD 36
#define GAME_GUESS_LINE 9
#define GAME_GUESS_FIELD 24

/* Header files  */
#include <wdlib.h>                 /* Window interface header  */
#include <stdio.h>                 /* Standard I/O header      */
#include <stdlib.h>                /* Standard library header  */
#include <time.h>                  /* Time functions header    */

/* A very few special purpose external variables */
char title_string(|44|);          /* Title and time string  */
char game_result_message(|36|);   /* Win or lose message    */
int  game_number;                 /* The object of the game */
char err_buf(|136|);              /* FSSL error msg buffer  */

/* Prototypes for application functions    */
void fs_error_warn(char *fn, int rc, int line);
int  wd_error_warn(char *, WDWI *, int parm1, void *parm2);
int  event_hd(WDWI *wdwi, int event, int parm1, void *parm2);
int  gamepop_hd(WDWI *wdwi, int event, int parm1, void *parm2);
int  browse_init(WDWI *);
void pfbars_init(WDWI *);
void game_init(WDWI *);
void game_play(WDWI *, WDINPUT *);
void time_update(WDWI *);
int  line_count(void);

/* Common open list structure used to open the BROWSER */
/* window and the GAME window.                         */
static  WDOLST olst_common = {
  "COMMON  ", /* Window name                    */
  0, 0,       /* Physical screen origin         */
  0, 0,       /* Number of rows, number of cols */
  3,  6,      /* Minimum window size            */
  NULL,       /* Border, title, cmdline color   */
              /* Window flags                   */
  WDW_BORDER+WDW_TITLE+
  WDW_ERROR_EVT+WDW_WARN_EVT,
              /* Border, title, cmdline attr.   */
  BRIGHT+REVERSE_VIDEO,
  0, 0,       /* Initial cursor row, col        */
  &event_hd,  /* Event handler function ptr     */
  100,        /* Event handler priority 16-239  */
  NULL,       /* Title text                     */
  NULL,       /* Cmdline text                   */
  NULL,       /* Border chars                   */
  NULL};      /* Address of "user data" field   */

/* The window structure used to open the GAMEPOP popup */
/* window.                                             */
static  WDOLST olst_gamepop = {
  "GAMEPOP ", /* Window name                    */
  15,18,      /* Physical screen origin         */
  3, 45,      /* Number of rows, number of cols */
  3, 45,      /* Minimum window size            */
  YELLOW,     /* Border, title, cmdline color   */
              /* Window flags                   */
  WDW_BORDER+WDW_TITLE+
  WDW_ERROR_EVT+WDW_WARN_EVT,
              /* Border, title, cmdline attr.   */
  BRIGHT,
  0, 0,       /* Initial cursor row, col        */
  &gamepop_hd,/* Event handler function ptr     */
  239,        /* Event handler priority 16-239  */
              /* Title text                     */
  "SAS/C Sample Game Results",
  NULL,       /* Cmdline text                   */
  NULL,       /* Border chars                   */
  NULL};      /* Address of "user data" field   */

/*  The main function begins here  */
void main() {

struct FS_TERMATTR *term_attr;    /* Terminal attribute structure ptr */
WDWI *browser, *game, *pfbars;    /* Pointers to the 3 primary windows*/
WDOLST *olst_pfbars;              /* Pointer to an open list structure*/
int rc;

term_attr = wdinit(err_buf);      /* Begin Window interface operations*/
if (term_attr == NULL) {
  fs_error_warn("wdinit",-1 ,(__LINE__-3));
 }

/* Modify the common open list structure with the  */
/* specifics of the the BROWSER window and then    */
/* open the window.                                */
strcpy(olst_common.name,   "BROWSER ");
olst_common.beg_row      = 0;
olst_common.beg_col      = 0;
olst_common.height       = term_attr->prim_row - 4;
olst_common.width        = term_attr->prim_col;
olst_common.color        = MAGENTA;
olst_common.title        = "SAS/C Sample Browser";
browser = wdopen(&olst_common, &rc);
if (browser == NULL) {
 fs_error_warn("wdopen", rc ,(__LINE__-3));
 }

/* Modify the common open list structure with the  */
/* specifics of the the GAME window and then open  */
/* the window.                                     */
strcpy(olst_common.name,   "GAME    ");
olst_common.beg_row      = 0;
olst_common.beg_col      = 15;
olst_common.height       = term_attr->prim_row - 4;
olst_common.width        = term_attr->prim_col - 30;
olst_common.color        = BLUE;
olst_common.title        = "SAS/C Sample Game";
game = wdopen(&olst_common, &rc);
if (game == NULL) {
 fs_error_warn("wdopen", rc ,(__LINE__-3));
 }

/* Use the wdrtolst() function to make a copy of   */
/* the common open list structure, modify it with  */
/* the specifics of the PFBARS window, then open   */
/* the window.                                     */
olst_pfbars = wdrtolst(game);
strcpy(olst_pfbars->name,   "PFBARS  ");
olst_pfbars->beg_row      = term_attr->prim_row - 4;
olst_pfbars->beg_col      = 0;
olst_pfbars->height       = 4;
olst_pfbars->width        = term_attr->prim_col;
olst_pfbars->color        = RED;
olst_pfbars->title        = "PF Key Assignments";
pfbars = wdopen(olst_pfbars, &rc);
if (pfbars == NULL) {
 fs_error_warn("wdopen", rc ,(__LINE__-3));
 }
free(olst_pfbars);  /* Once the window is open, the WDOLST */
                    /* structure is no longer required.    */

/* Present the windows in the desired order(BROWSER on */
/* top, GAME behind it, and PFBARS at the back).       */
/* However, due to the size and position of the three  */
/* windows, PFBARS will still be completely visible.   */
wdsettop(pfbars);
wdsettop(game);
wdsettop(browser);

/* Call the Window interface dispatcher.  All further */
/* activity will be controlled by her.                */
wdwait();

/* The flow of control will only reach this logical   */
/* point when all windows have been terminated.       */
wdterm();

} /* end of the main() function */


#eject
/* This is the handler for all display manager events */
/* (except those events associatted with the GAMEPOP  */
/* popup window, which has its own seperate handler). */
int  event_hd(WDWI *wdwi, int event, int parm1, void *parm2) {
WDWI *pfbars;        /* Pointer to the PFBARS window  */
WDWI *game;          /* Pointer to the GAME window    */
WDWI *browser;       /* Pointer to the BROWSER window */

/* Get the pointer values from the dispatcher. */
pfbars  = wdinqwd("PFBARS  ");
game    = wdinqwd("GAME    ");
browser = wdinqwd("BROWSER ");

/*  Update the time and date on all events except */
/*  initialization and termination events.  At    */
/*  these two events, the PFBARS window may not   */
/*  always be available.                          */
if (event != WEVT_INIT && event != WEVT_TERM) time_update(pfbars);

/* The action taken by the handler depends on what kind of */
/* event has occurred.                                     */
switch (event)
 {
  case WEVT_PFK:  /* A PF Key was depressed, */
   switch (parm1) /* which one was it?       */
    {
     case PF_7:  /* Scroll all eligible subwindows up a full page */
     case PF_19: /* if the active window is the BROWSER window.   */
      if (strcmp(wdwi->name,"BROWSER ") == 0)
       wdscroll(wdwi, WD_SCROLL_ALL, 0, WD_UP, WSCR_PAGE);
      break;

     case PF_8:  /* Scroll all eligible subwindows down a full page */
     case PF_20: /* if the active window is the BROWSER window.     */
      if (strcmp(wdwi->name,"BROWSER ") == 0)
       wdscroll(wdwi, WD_SCROLL_ALL, 0, WD_DOWN, WSCR_PAGE);
      break;

     case PF_10: /* Scroll all eligible subwindows left a full page */
     case PF_22:
      wdscroll(wdwi, WD_SCROLL_ALL, 0, WD_LEFT, WSCR_PAGE);
      break;

     case PF_11: /* Scroll all eligible subwindows right a full page */
     case PF_23:
      wdscroll(wdwi, WD_SCROLL_ALL, 0, WD_RIGHT, WSCR_PAGE);
      break;

     case PF_3:  /* Terminate the window interface environment */
     case PF_15:
      return(WRET_TERM);
      break;

     case PF_9:  /* Select a new "top" window */
     case PF_21:
      wdsetnxt(); /* Put the next window on top...           */
                  /* if that window happens to be PFBARS.... */
      if (strcmp(wdinqtop()->name,"PFBARS  ") == 0)
       {
                  /* if PFBARS is not overlapping ANY other window...*/
                  /* put some other window on top.  (Because the     */
                  /* PFBARS window doesn't DO anything! It just pre- */
                  /* sents information about what the PF Keys do.)   */
        if (wdovlap(pfbars,game)    == 0 &&
            wdovlap(pfbars,browser) == 0) wdsetnxt();
       }
      break;

     case PF_2:  /* Move the current window according to subsequent */
     case PF_14: /* cursor position.                                */
      wdmove(WD_ANY_KEY, 0);
      break;

     case PF_4:  /* Change the size of the current window according */
     case PF_16: /* to subsequent cursor position.                  */
      wdgrow(WD_ANY_KEY, 0);
      break;

     case PF_5:  /* Zoom the current window to the physical maximum */
     case PF_17: /* -OR- Unzoom the current window to original size */
      wdzoom(wdwi, WD_ZOOM_TOGGLE);
      break;

     default:    /* No action is defined for these PF Keys          */
     case PF_1:
     case PF_6:
     case PF_12:
     case PF_13:
     case PF_18:
     case PF_24:
      break;
    }   /* end of switch(parm1) */
    return (WRET_PASSTHRU);
    break;

  case WEVT_WARN:  /* A Window interface warning has been detected, */
                   /* Call the routine that prints the message.     */
    return(wd_error_warn("WEVT_WARN", wdwi, parm1, parm2));
    break;

  case WEVT_ERROR: /* A Window interface error has been detected,   */
                   /* Call the routine that prints the message.     */
    return(wd_error_warn("WEVT_ERROR", wdwi, parm1, parm2));
    break;

  case WEVT_INIT:  /* A new window has just opened up!  Go paint it */
                   /* up with the appropriate stuff!                */
   if (strcmp(wdwi->name,"BROWSER ") == 0) return(browse_init(wdwi));
   if (strcmp(wdwi->name,"PFBARS  ") == 0) pfbars_init(wdwi);
   if (strcmp(wdwi->name,"GAME    ") == 0) game_init(wdwi);
   return(WRET_PASSTHRU);
   break;

  case WEVT_ENTER: /* The operator pressed enter while the cursor */
                   /* was in some window.  If it was the GAME     */
                   /* window, play the game; otherwise do nothing.*/
   if (strcmp(wdwi->name,"GAME    ") == 0) game_play(wdwi,parm2);
   return (WRET_PASSTHRU);
   break;

  default:         /* For all other events, do nothing and return   */
   return (WRET_PASSTHRU);
   break;
 }  /* end of switch(event) */
} /* end of event_hd() */

#eject
/* This function is called by the event handler to initialize the */
/* BROWSER window.                                                */
int browse_init(WDWI *browser) {
WDSW *sub_browser;         /* Pointer to the browsing subwindow  */
char buf(|80|);            /* A buffer to read the records into  */
int  program_size;         /* Number of source lines in this pgm */
FILE *fp;
int i, rc;

/* Call the line_count function to determine the number of source */
/* lines in this program.  That number will be used to determine  */
/* the size of the subwindow in which the browsing takes place.   */
program_size = line_count();

/* Define a large subwindow in which to place records for browsing */
/* This particular technique is not put forward as "best" or even  */
/* as particularly effecient, but it does illustrate the use of    */
/* subwindows and subwindow scrolling nicely.                      */
sub_browser = wddfsw(browser, 0, 0, program_size,
    browser->use_width, 0, 0, " ", PROTECTED, WHITE, ' ', WD_VERT_DATA,
    &rc);

/* IMPORTANT!!!!! You will need to modify the filename to whatever */
/* your local installer chose.  A nice feature of this sample is   */
/* that it browses its own source code; allowing you to following  */
/* the bouncing ball!  Also, the actual file name is operating     */
/* system dependent; which is no problem since SAS/C automatically */
/* defines CMS as a symbol when compiling on CMS and OSVS when     */
/* compiling on an OS-derivative operating system.                 */
#ifdef CMS
fp = fopen("cms:LCSAMPLE MACLIB * MEMBER WDSAMPLE","rb");
#else
fp = fopen("dsn:SASC.SAMPLE(WDSAMPLE)","rb");
#endif
if (fp == NULL) {
  printf("Unable to open file for browsing\n");
  return(WEVT_TERM);
 }
/* Read the records and fill up the subwindow */
for(i=0; i < program_size ; i++) {
  rc = fread(buf,80,1,fp);
  if (feof(fp)) break;
  if (rc == 0 ) {
    printf("Unsuccessful fread during subwindow load\n");
    return(WRET_FAILED);
   }
  /* Place the record into the subwindow */
  wdupdsw(sub_browser, UPD_TEXT, i, 0, buf);
 } /* end of for(...) */
} /* end of browse_init() */

/* This function is called by the event handler to initialize the */
/* PFBARS window.                                                 */
void pfbars_init(WDWI *pfbars) {
char *pf_string1 = "  PF1   PF2   PF3   PF4   PF5   PF6   PF7  "
                   "PF8   PF9   PF10  PF11   PF12";

char *pf_string2 = "  NULL  Move  End   Grow  Zoom  NULL  Up   "
                   "Down  Next  LEFT  RIGHT  NULL";

/* Cause the current time and date to be placed in the PFBARS title */
time_update(pfbars);
/* Paint in the PF Key numbers and values */
wdupdln(pfbars, DEF_FIELD, 0, 0, pf_string1, PROTECTED, RED,
        USE_TEXT_LEN, 0);
wdupdln(pfbars, DEF_FIELD, 1, 0, pf_string2, PROTECTED, RED,
        USE_TEXT_LEN, 0);
} /* end of pfbars_init() */

/* This function is called by pfbars_init() and event_hd() to */
/* keep the time and date in the PFBARS title up-to-date.     */
void time_update(WDWI *pfbars) {
char *time_string;
time_t now;

time(&now);                 /* Get the current Greenwich Mean Time  */
time_string = ctime(&now);  /* and convert it to something readable */
sprintf(title_string,"PF Key Assignments--%.24s",time_string);
/* Update the title field in the PFBARS window */
wdupdln(pfbars, UPD_TEXT, WD_TITLE, 0, title_string,
        0,0, USE_TEXT_LEN, BLANK);
} /* end of time_update() */

/* This function is called by the event handler to initialize the */
/* GAME window.                                                   */
void game_init(WDWI *game) {
time_t now;

/* Use the current "seconds after the minute" to seed the psuedo- */
/* random number generator.  Then generate a psuedorandom number. */
time(&now);
srand(gmtime(&now)->tm_sec);
for(;;) {
  game_number = rand();
   /* Ensure that the number is between 1 and 1000, inclusive */
  if (game_number > 0 && game_number <= 1000) break;
 } /* end of for(...) */

/* Paint in the game instructions and initial field values */
/* Notice that when defining a field, all of the parameters*/
/* to wdupdln() are required.                              */
wdupdln(game,DEF_FIELD, 0, 5,
        "I have randomly chosen a number between", PROTECTED, BLUE,
        USE_TEXT_LEN, 0);
wdupdln(game,DEF_FIELD, 1, 5,
        "1 and 1000.  I'll give you 20 guesses.", PROTECTED, BLUE,
        USE_TEXT_LEN, 0);
wdupdln(game,DEF_FIELD, 2, 5,
        "Each time I'll tell you if you are too", PROTECTED, BLUE,
        USE_TEXT_LEN, 0);
wdupdln(game,DEF_FIELD, 3, 5,
        "high or too low. ", PROTECTED, BLUE, USE_TEXT_LEN, 0);
/* Line 4 is blank */
wdupdln(game,DEF_FIELD, 5, 5,
        "Guesses Left    Last Guess     Result", PROTECTED, BLUE,
        USE_TEXT_LEN, 0);
wdupdln(game,DEF_FIELD, GAME_RESULT_LINE, GAME_RESULT_GUESSES_LEFT,
        "20",  PROTECTED, GREEN, USE_TEXT_LEN, 0);
wdupdln(game,DEF_FIELD, GAME_RESULT_LINE, GAME_RESULT_LAST_GUESS,
        "0000", PROTECTED, GREEN, USE_TEXT_LEN, 0);
wdupdln(game,DEF_FIELD, GAME_RESULT_LINE, GAME_RESULT_FIELD,
        "Good Luck", PROTECTED, GREEN, USE_TEXT_LEN, 0);
/* Line 7 is blank */
wdupdln(game,DEF_FIELD, 8, 21,
        "Next Guess", PROTECTED, BLUE, USE_TEXT_LEN, 0);
wdupdln(game,DEF_FIELD, GAME_GUESS_LINE, GAME_GUESS_FIELD,
        "0000", BRIGHT+NUMERIC, CYAN, USE_TEXT_LEN, 0);
wdsetlcr(game,GAME_GUESS_LINE,GAME_GUESS_FIELD);
} /* end of game_init() */

/* This function is called by the event handler to actually play  */
/* the game when the enter key is pressed.                        */
void game_play(WDWI *game, WDINPUT *input) {
int guess_value;
char *text_ptr;
int  text_max_len;
char guess_left_text(|3|) = "\0\0\0";
int  guess_left_value;
char guess_result_text(|10|);
char previous_guess_text(|5|) = "\0\0\0\0\0";

/* Determine if the player has correctly guessed the number.*/
/* If the player actually entered a guess, use the WD_INPUT */
/* structure to access the guess  value.  If the player did */
/* not "modify" the guess field, then the program is forced */
/* to "reuse" the previous guess.  The previous guess is    */
/* recovered by directly accessing the data in the window   */
/* via the wdgetln() function.                              */
if (input->first_inp_field != NULL)
  guess_value = atoi(input->first_inp_field->inp_data);
 else
  {
   wdgetln(game, GET_TEXT, GAME_GUESS_LINE, GAME_GUESS_FIELD,
           &text_ptr, NULL, NULL, &text_max_len, NULL);
   guess_value = atoi(text_ptr);
  }

if (guess_value == game_number) {
   strcpy(game_result_message,"You won! Hit any PF to continue.");
    /* Cause a popup window to be opened and displayed.  Note */
    /* that the GAMEPOP window has a unique event handler.    */
    /* This is not required, but it does lead to a clearer    */
    /* programming style.                                     */
   wdpopup(&olst_gamepop,0);
    /* Cause another initialization event to happen for the   */
    /* GAME window.  This is how the game is reset for further*/
    /* play.  (The event will be handled asynchronously.)     */
   wdpostev(game,WEVT_INIT,NULL,NULL,WD_WINDOW_PRIORITY,NULL);
   return;
 }

/* Retrieve the number of guesses remaining directly from the */
/* data in the window.  Of course, this same data could have  */
/* been kept in a program variable, but this is a sample pgm! */
wdgetln(game, GET_TEXT, GAME_RESULT_LINE, GAME_RESULT_GUESSES_LEFT,
        &text_ptr, NULL, NULL, &text_max_len, NULL);
guess_left_value = atoi(text_ptr);

/* Deterimine if the player has run out of guesses */
if (guess_left_value == 1) {
   strcpy(game_result_message,"You lost. Hit any PF to continue.");
    /* Process the popup window in the same manner as above.  */
   wdpopup(&olst_gamepop,0);
   wdpostev(game,WEVT_INIT,NULL,NULL,WD_WINDOW_PRIORITY,NULL);
   return;
 }

/* Having neither won nor lost; prepare for another round  */
/* by decrementing the number of remaining guesses, saving */
/* the previous guess, and determining whether the player  */
/* guessed high or low.                                    */
sprintf(guess_left_text,"%-2d\0",--guess_left_value);
wdupdln(game,UPD_TEXT, GAME_RESULT_LINE, GAME_RESULT_GUESSES_LEFT,
        guess_left_text, 0, 0, USE_TEXT_LEN, 0);
sprintf(previous_guess_text,"%-4d\0",guess_value);
wdupdln(game,UPD_TEXT, GAME_RESULT_LINE, GAME_RESULT_LAST_GUESS,
        previous_guess_text, 0, 0, USE_TEXT_LEN, 0);
if (guess_value > game_number) strcpy(guess_result_text,"Too big");
                          else strcpy(guess_result_text,"Too small");
wdupdln(game,UPD_TEXT, GAME_RESULT_LINE, GAME_RESULT_FIELD,
        guess_result_text, 0, 0, USE_TEXT_LEN, 0);
wdsetlcr(game,GAME_GUESS_LINE,GAME_GUESS_FIELD);
} /* end of game_play() */

/* This is the unique event handler for the GAMEPOP popup window  */
/* A unique handler is NOT required for a window, but this one    */
/* demonstrates that it is a possible style consideration.        */
int  gamepop_hd(WDWI *wdwi, int event, int parm1, void *parm2) {
switch (event) {
  case WEVT_INIT:  /* Display the result of the game */
   wdalarm();      /* Sound the horn, in glory or shame */
   wdupdln(wdwi,DEF_FIELD, 0, 0, game_result_message, PROTECTED,
           YELLOW, USE_TEXT_LEN, 0);
   return(WRET_PASSTHRU);
   break;

  case WEVT_PFK:   /* Close the popup window on any PF key */
    return(WRET_TERM);
    break;
  case WEVT_WARN:  /* A Window interface warning has been detected, */
                   /* Call the routine that prints the message.     */
    return(wd_error_warn("WEVT_WARN", wdwi, parm1, parm2));
    break;

  case WEVT_ERROR: /* A Window interface error has been detected,   */
                   /* Call the routine that prints the message.     */
    return(wd_error_warn("WEVT_ERROR", wdwi, parm1, parm2));
    break;

  default: return(WRET_PASSTHRU); break;
 }  /* end of switch(event) */
} /* end of gamepop_hd() */

#eject
/* This function is called by both the common event handler and */
/* the unique GAMEPOP handler.  It's job is to emit Window      */
/* interface warnings and errors.                               */
int wd_error_warn(char *type, WDWI *wdwi, int parm1, void *parm2) {
char window_name(|8|);

if (wdwi) memcpy(window_name,wdwi->name,8);
 else strcpy(window_name,"NULL    ");

printf("%s  rc = %d for window = %.8s warn_text  = %.80s\n",
              type, parm1, window_name, (char *) parm2);
return(parm1);  /* reflect back error code */
} /* end of wd_error_warn() */

/* This function issues FSSL warnings and errors */
void fs_error_warn(char *fn, int rc, int line) {
if (!rc) return;
if (rc > 0)
 printf("%s warning rc = %d at line %d\n", fn, rc, line);
 else
 printf("%s error   rc = %d at line %d\n", fn, rc, line);
printf("error text %s\n\n", err_buf);
} /* end of fs_error_warn() */

/* This is an unusual function.  It makes use of the __LINE__ */
/* ANSI macro which always contains the number of the current */
/* source line.  Since this function is at the bottom of the  */
/* source program, the actual size of the source can be dyn-  */
/* amically determined at runtime.                            */
int line_count(void) {
return(__LINE__ + 1);
} /* end of line_count() and the end of all source code */

Copyright (c) 2000 SAS Institute Inc. All Rights Reserved.
Terms of Use & Legal Information | Privacy Statement