1*23851Sjerry /* #define OLD_BSD if you're running < 4.2 bsd */ 213576Sdlw /* 322991Skre * Copyright (c) 1980 Regents of the University of California. 422991Skre * All rights reserved. The Berkeley software License Agreement 522991Skre * specifies the terms and conditions for redistribution. 613576Sdlw * 7*23851Sjerry * @(#)trpfpe_.c 5.3 07/08/85 822991Skre * 922996Skre * 1013576Sdlw * Fortran floating-point error handler 1113576Sdlw * 1213576Sdlw * Synopsis: 1313576Sdlw * call trpfpe (n, retval) 1413576Sdlw * causes floating point faults to be trapped, with the 1513576Sdlw * first 'n' errors getting a message printed. 1613576Sdlw * 'retval' is put in place of the bad result. 1713576Sdlw * k = fpecnt() 1813576Sdlw * causes 'k' to get the number of errors since the 1913576Sdlw * last call to trpfpe(). 2013576Sdlw * 2113576Sdlw * common /fpeflt/ fpflag 2213576Sdlw * logical fpflag 2313576Sdlw * fpflag will become .true. on faults 2413576Sdlw * 2513576Sdlw * David Wasley, UCBerkeley, June 1983. 2613576Sdlw */ 2713576Sdlw 2813576Sdlw 2913576Sdlw #include <stdio.h> 3013576Sdlw #include <signal.h> 3113576Sdlw #include "opcodes.h" 3213576Sdlw #include "operand.h" 3313576Sdlw #include "../libI77/fiodefs.h" 3413576Sdlw 3513576Sdlw #define SIG_VAL int (*)() 3613576Sdlw 3713576Sdlw #if vax /* only works on VAXen */ 3813576Sdlw 3913576Sdlw struct arglist { /* what AP points to */ 4013576Sdlw long al_numarg; /* only true in CALLS format */ 4113576Sdlw long al_arg[256]; 4213576Sdlw }; 4313576Sdlw 4413576Sdlw struct cframe { /* VAX call frame */ 4513576Sdlw long cf_handler; 4613576Sdlw unsigned short cf_psw; 4713576Sdlw unsigned short cf_mask; 4813576Sdlw struct arglist *cf_ap; 4913576Sdlw struct cframe *cf_fp; 5013576Sdlw char *cf_pc; 5113576Sdlw }; 5213576Sdlw 5313576Sdlw /* 5413576Sdlw * bits in the PSW 5513576Sdlw */ 5613576Sdlw #define PSW_V 0x2 5713576Sdlw #define PSW_FU 0x40 5813576Sdlw #define PSW_IV 0x20 5913576Sdlw 6013576Sdlw /* 6113576Sdlw * where the registers are stored as we see them in the handler 6213576Sdlw */ 6313576Sdlw struct reg0_6 { 6413576Sdlw long reg[7]; 6513576Sdlw }; 6613576Sdlw 6713576Sdlw struct reg7_11 { 6813576Sdlw long reg[5]; 6913576Sdlw }; 7013576Sdlw 7113576Sdlw #define iR0 reg0_6->reg[0] 7213576Sdlw #define iR1 reg0_6->reg[1] 7313576Sdlw #define iR2 reg0_6->reg[2] 7413576Sdlw #define iR3 reg0_6->reg[3] 7513576Sdlw #define iR4 reg0_6->reg[4] 7613576Sdlw #define iR5 reg0_6->reg[5] 7713576Sdlw #define iR6 reg0_6->reg[6] 7813576Sdlw #define iR7 reg7_11->reg[0] 7913576Sdlw #define iR8 reg7_11->reg[1] 8013576Sdlw #define iR9 reg7_11->reg[2] 8113576Sdlw #define iR10 reg7_11->reg[3] 8213576Sdlw #define iR11 reg7_11->reg[4] 8313576Sdlw 8413576Sdlw union objects { /* for load/store */ 8513576Sdlw char ua_byte; 8613576Sdlw short ua_word; 8713576Sdlw long ua_long; 8813576Sdlw float ua_float; 8913576Sdlw double ua_double; 9013576Sdlw union objects *ua_anything; 9113576Sdlw }; 9213576Sdlw 9313576Sdlw typedef union objects anything; 9413576Sdlw enum object_type { BYTE, WORD, LONG, FLOAT, QUAD, DOUBLE, UNKNOWN }; 9513576Sdlw 9613576Sdlw 9713576Sdlw /* 9813576Sdlw * assembly language assist 9913576Sdlw * There are some things you just can't do in C 10013576Sdlw */ 10113576Sdlw asm(".text"); 10213576Sdlw 10313576Sdlw struct cframe *myfp(); 10413576Sdlw asm("_myfp: .word 0x0"); 10513576Sdlw asm("movl 12(fp),r0"); 10613576Sdlw asm("ret"); 10713576Sdlw 10813576Sdlw struct arglist *myap(); 10913576Sdlw asm("_myap: .word 0x0"); 11013576Sdlw asm("movl 8(fp),r0"); 11113576Sdlw asm("ret"); 11213576Sdlw 11313576Sdlw char *mysp(); 11413576Sdlw asm("_mysp: .word 0x0"); 11513576Sdlw asm("extzv $30,$2,4(fp),r0"); 11613576Sdlw asm("addl2 ap,r0"); /* SP in caller is AP+4 here + SPA bits! */ 11713576Sdlw asm("addl2 $4,r0"); 11813576Sdlw asm("ret"); 11913576Sdlw 12013576Sdlw char *mypc(); 12113576Sdlw asm("_mypc: .word 0x0"); 12213576Sdlw asm("movl 16(fp),r0"); 12313576Sdlw asm("ret"); 12413576Sdlw 12513576Sdlw asm(".data"); 12613576Sdlw 12713576Sdlw 12813576Sdlw /* 12913576Sdlw * Where interrupted objects are 13013576Sdlw */ 13113576Sdlw static struct cframe **ifp; /* addr of saved FP */ 13213576Sdlw static struct arglist **iap; /* addr of saved AP */ 13313576Sdlw static char *isp; /* value of interrupted SP */ 13413576Sdlw static char **ipc; /* addr of saved PC */ 13513576Sdlw static struct reg0_6 *reg0_6;/* registers 0-6 are saved on the exception */ 13613576Sdlw static struct reg7_11 *reg7_11;/* we save 7-11 by our entry mask */ 13713576Sdlw static anything *result_addr; /* where the dummy result goes */ 13813576Sdlw static enum object_type result_type; /* what kind of object it is */ 13913576Sdlw 14013576Sdlw /* 14113576Sdlw * some globals 14213576Sdlw */ 14313576Sdlw static union { 14413576Sdlw long rv_long[2]; 14513576Sdlw float rv_float; 14613576Sdlw double rv_double; 14713576Sdlw } retval; /* the user specified dummy result */ 14813576Sdlw static int max_messages = 1; /* the user can tell us */ 14913576Sdlw static int fpe_count = 0; /* how bad is it ? */ 15013576Sdlw long fpeflt_ = 0; /* fortran "common /fpeflt/ flag" */ 15113576Sdlw static int (*sigfpe_dfl)() = SIG_DFL; /* if we can't fix it ... */ 15213576Sdlw 15313576Sdlw /* 15413576Sdlw * The fortran unit control table 15513576Sdlw */ 15613576Sdlw extern unit units[]; 15713576Sdlw 15813576Sdlw /* 15913576Sdlw * Fortran message table is in main 16013576Sdlw */ 16113576Sdlw struct msgtbl { 16213576Sdlw char *mesg; 16313576Sdlw int dummy; 16413576Sdlw }; 16513576Sdlw extern struct msgtbl act_fpe[]; 16613576Sdlw 16713576Sdlw 16813576Sdlw /* 16913576Sdlw * Get the address of the (saved) next operand & update saved PC. 17013576Sdlw * The major purpose of this is to determine where to store the result. 17113576Sdlw * There is one case we can't deal with: -(SP) or (SP)+ 17213576Sdlw * since we can't change the size of the stack. 17313576Sdlw * Let's just hope compilers don't generate that for results. 17413576Sdlw */ 17513576Sdlw 17613576Sdlw anything * 17713576Sdlw get_operand (oper_size) 17813576Sdlw int oper_size; /* size of operand we expect */ 17913576Sdlw { 18013576Sdlw register int regnum; 18113576Sdlw register int operand_code; 18213576Sdlw int index; 18313576Sdlw anything *oper_addr; 18413576Sdlw anything *reg_addr; 18513576Sdlw 18613576Sdlw regnum = (**ipc & 0xf); 18713576Sdlw if (regnum == PC) 18813576Sdlw operand_code = (*(*ipc)++ & 0xff); 18913576Sdlw else 19013576Sdlw operand_code = (*(*ipc)++ & 0xf0); 19113576Sdlw if (regnum <= R6) 19213576Sdlw reg_addr = (anything *)®0_6->reg[regnum]; 19313576Sdlw else if (regnum <= R11) 19413576Sdlw reg_addr = (anything *)®7_11->reg[regnum]; 19513576Sdlw else if (regnum == AP) 19613576Sdlw reg_addr = (anything *)iap; 19713576Sdlw else if (regnum == FP) 19813576Sdlw reg_addr = (anything *)ifp; 19913576Sdlw else if (regnum == SP) 20013576Sdlw reg_addr = (anything *)&isp; /* We saved this ourselves */ 20113576Sdlw else if (regnum == PC) 20213576Sdlw reg_addr = (anything *)ipc; 20313576Sdlw 20413576Sdlw 20513576Sdlw switch (operand_code) 20613576Sdlw { 20713576Sdlw case IMMEDIATE: 20813576Sdlw oper_addr = (anything *)(*ipc); 20913576Sdlw *ipc += oper_size; 21013576Sdlw return(oper_addr); 21113576Sdlw 21213576Sdlw case ABSOLUTE: 21313576Sdlw oper_addr = (anything *)(**ipc); 21413576Sdlw *ipc += sizeof (anything *); 21513576Sdlw return(oper_addr); 21613576Sdlw 21713576Sdlw case LITERAL0: 21813576Sdlw case LITERAL1: 21913576Sdlw case LITERAL2: 22013576Sdlw case LITERAL3: 22113576Sdlw /* we don't care about the address of these */ 22213576Sdlw return((anything *)0); 22313576Sdlw 22413576Sdlw case INDEXED: 22513576Sdlw index = reg_addr->ua_long * oper_size; 22613576Sdlw oper_addr = (anything *)(get_operand(sizeof (long))->ua_long + index); 22713576Sdlw return(oper_addr); 22813576Sdlw 22913576Sdlw case REGISTER: 23013576Sdlw return(reg_addr); 23113576Sdlw 23213576Sdlw case REGDEFERED: 23313576Sdlw return(reg_addr->ua_anything); 23413576Sdlw 23513576Sdlw case AUTODEC: 23613576Sdlw if (regnum == SP) 23713576Sdlw { 23813576Sdlw fprintf(stderr, "trp: can't fix -(SP) operand\n"); 23913576Sdlw exit(1); 24013576Sdlw } 24113576Sdlw reg_addr->ua_long -= oper_size; 24213576Sdlw oper_addr = reg_addr->ua_anything; 24313576Sdlw return(oper_addr); 24413576Sdlw 24513576Sdlw case AUTOINC: 24613576Sdlw if (regnum == SP) 24713576Sdlw { 24813576Sdlw fprintf(stderr, "trp: can't fix (SP)+ operand\n"); 24913576Sdlw exit(1); 25013576Sdlw } 25113576Sdlw oper_addr = reg_addr->ua_anything; 25213576Sdlw reg_addr->ua_long += oper_size; 25313576Sdlw return(oper_addr); 25413576Sdlw 25513576Sdlw case AUTOINCDEF: 25613576Sdlw if (regnum == SP) 25713576Sdlw { 25813576Sdlw fprintf(stderr, "trp: can't fix @(SP)+ operand\n"); 25913576Sdlw exit(1); 26013576Sdlw } 26113576Sdlw oper_addr = (reg_addr->ua_anything)->ua_anything; 26213576Sdlw reg_addr->ua_long += sizeof (anything *); 26313576Sdlw return(oper_addr); 26413576Sdlw 26513576Sdlw case BYTEDISP: 26613576Sdlw case BYTEREL: 26713626Sdlw index = ((anything *)(*ipc))->ua_byte; 26813626Sdlw *ipc += sizeof (char); /* do it now in case reg==PC */ 26913626Sdlw oper_addr = (anything *)(index + reg_addr->ua_long); 27013576Sdlw return(oper_addr); 27113576Sdlw 27213576Sdlw case BYTEDISPDEF: 27313576Sdlw case BYTERELDEF: 27413626Sdlw index = ((anything *)(*ipc))->ua_byte; 27513626Sdlw *ipc += sizeof (char); /* do it now in case reg==PC */ 27613626Sdlw oper_addr = (anything *)(index + reg_addr->ua_long); 27713576Sdlw oper_addr = oper_addr->ua_anything; 27813576Sdlw return(oper_addr); 27913576Sdlw 28013576Sdlw case WORDDISP: 28113576Sdlw case WORDREL: 28213626Sdlw index = ((anything *)(*ipc))->ua_word; 28313626Sdlw *ipc += sizeof (short); /* do it now in case reg==PC */ 28413626Sdlw oper_addr = (anything *)(index + reg_addr->ua_long); 28513576Sdlw return(oper_addr); 28613576Sdlw 28713576Sdlw case WORDDISPDEF: 28813576Sdlw case WORDRELDEF: 28913626Sdlw index = ((anything *)(*ipc))->ua_word; 29013626Sdlw *ipc += sizeof (short); /* do it now in case reg==PC */ 29113626Sdlw oper_addr = (anything *)(index + reg_addr->ua_long); 29213576Sdlw oper_addr = oper_addr->ua_anything; 29313576Sdlw return(oper_addr); 29413576Sdlw 29513576Sdlw case LONGDISP: 29613576Sdlw case LONGREL: 29713626Sdlw index = ((anything *)(*ipc))->ua_long; 29813626Sdlw *ipc += sizeof (long); /* do it now in case reg==PC */ 29913626Sdlw oper_addr = (anything *)(index + reg_addr->ua_long); 30013576Sdlw return(oper_addr); 30113576Sdlw 30213576Sdlw case LONGDISPDEF: 30313576Sdlw case LONGRELDEF: 30413626Sdlw index = ((anything *)(*ipc))->ua_long; 30513626Sdlw *ipc += sizeof (long); /* do it now in case reg==PC */ 30613626Sdlw oper_addr = (anything *)(index + reg_addr->ua_long); 30713576Sdlw oper_addr = oper_addr->ua_anything; 30813576Sdlw return(oper_addr); 30913576Sdlw 31013576Sdlw /* NOTREACHED */ 31113576Sdlw } 31213576Sdlw } 31313576Sdlw 31413576Sdlw /* 31513576Sdlw * Trap & repair floating exceptions so that a program may proceed. 31613576Sdlw * There is no notion of "correctness" here; just the ability to continue. 31713576Sdlw * 31813576Sdlw * The on_fpe() routine first checks the type code to see if the 31913576Sdlw * exception is repairable. If so, it checks the opcode to see if 32013576Sdlw * it is one that it knows. If this is true, it then simulates the 32113576Sdlw * VAX cpu in retrieving operands in order to increment iPC correctly. 32213576Sdlw * It notes where the result of the operation would have been stored 32313576Sdlw * and substitutes a previously supplied value. 32413576Sdlw */ 32513576Sdlw 32613576Sdlw #ifdef OLD_BSD 32713576Sdlw on_fpe(signo, code, myaddr, pc, ps) 32813576Sdlw int signo, code, ps; 32913576Sdlw char *myaddr, *pc; 33013576Sdlw #else 33113576Sdlw on_fpe(signo, code, sc, grbg) 33213576Sdlw int signo, code; 33313576Sdlw struct sigcontext *sc; 33413576Sdlw #endif 33513576Sdlw { 33613576Sdlw /* 33713576Sdlw * There must be at least 5 register variables here 33813576Sdlw * so our entry mask will save R11-R7. 33913576Sdlw */ 34013576Sdlw register long *stk; 34113576Sdlw register long *sp; 34213576Sdlw register struct arglist *ap; 34313576Sdlw register struct cframe *fp; 34413576Sdlw register FILE *ef; 34513576Sdlw 34613576Sdlw ef = units[STDERR].ufd; /* fortran error stream */ 34713576Sdlw 34813576Sdlw switch (code) 34913576Sdlw { 35013576Sdlw case FPE_INTOVF_TRAP: /* integer overflow */ 35113576Sdlw case FPE_INTDIV_TRAP: /* integer divide by zero */ 35213576Sdlw case FPE_FLTOVF_TRAP: /* floating overflow */ 35313576Sdlw case FPE_FLTDIV_TRAP: /* floating/decimal divide by zero */ 35413576Sdlw case FPE_FLTUND_TRAP: /* floating underflow */ 35513576Sdlw case FPE_DECOVF_TRAP: /* decimal overflow */ 35613576Sdlw case FPE_SUBRNG_TRAP: /* subscript out of range */ 35713576Sdlw default: 35813576Sdlw cant_fix: 35913576Sdlw if (sigfpe_dfl > (SIG_VAL)7) /* user specified */ 36013576Sdlw #ifdef OLD_BSD 36113576Sdlw return((*sigfpe_dfl)(signo, code, myaddr, pc, ps)); 36213576Sdlw #else 36313576Sdlw return((*sigfpe_dfl)(signo, code, sc, grbg)); 36413576Sdlw #endif 36513576Sdlw else 36613576Sdlw #ifdef OLD_BSD 36713576Sdlw sigdie(signo, code, myaddr, pc, ps); 36813576Sdlw #else 36913576Sdlw sigdie(signo, code, sc, grbg); 37013576Sdlw #endif 37113576Sdlw /* NOTREACHED */ 37213576Sdlw 37313576Sdlw case FPE_FLTOVF_FAULT: /* floating overflow fault */ 37413576Sdlw case FPE_FLTDIV_FAULT: /* divide by zero floating fault */ 37513576Sdlw case FPE_FLTUND_FAULT: /* floating underflow fault */ 37613576Sdlw if (++fpe_count <= max_messages) { 37713576Sdlw fprintf(ef, "trpfpe: %s", 37813576Sdlw act_fpe[code-1].mesg); 37913576Sdlw if (fpe_count == max_messages) 38013576Sdlw fprintf(ef, ": No more messages will be printed.\n"); 38113576Sdlw else 38213576Sdlw fputc('\n', ef); 38313576Sdlw } 38413576Sdlw fpeflt_ = -1; 38513576Sdlw break; 38613576Sdlw } 38713576Sdlw 38813576Sdlw ap = myap(); /* my arglist pointer */ 38913576Sdlw fp = myfp(); /* my frame pointer */ 39013576Sdlw ifp = &(fp->cf_fp)->cf_fp; /* user's stored in next frame back */ 39113576Sdlw iap = &(fp->cf_fp)->cf_ap; 39213576Sdlw /* 39313576Sdlw * these are likely to be system dependent 39413576Sdlw */ 39513576Sdlw reg0_6 = (struct reg0_6 *)((char *)fp->cf_fp + sizeof (struct cframe)); 39613576Sdlw reg7_11 = (struct reg7_11 *)((char *)fp->cf_fp - sizeof (struct reg7_11)); 39713576Sdlw 39813576Sdlw #ifdef OLD_BSD 39913576Sdlw ipc = &pc; 40013576Sdlw isp = (char *)&ap->al_arg[ap->al_numarg + 2]; /* assumes 2 dummys */ 40113576Sdlw ps &= ~(PSW_V|PSW_FU); 40213576Sdlw #else 40313576Sdlw ipc = (char **)&sc->sc_pc; 40414635Sdlw isp = (char *)sc + sizeof (struct sigcontext); 40513576Sdlw sc->sc_ps &= ~(PSW_V|PSW_FU); 40613576Sdlw #endif 40713576Sdlw 40813576Sdlw 40913576Sdlw switch (*(*ipc)++) 41013576Sdlw { 41113576Sdlw case ADDD3: 41213576Sdlw case DIVD3: 41313576Sdlw case MULD3: 41413576Sdlw case SUBD3: 41513576Sdlw (void) get_operand(sizeof (double)); 41613576Sdlw /* intentional fall-thru */ 41713576Sdlw 41813576Sdlw case ADDD2: 41913576Sdlw case DIVD2: 42013576Sdlw case MULD2: 42113576Sdlw case SUBD2: 42213576Sdlw case MNEGD: 42313576Sdlw case MOVD: 42413576Sdlw (void) get_operand(sizeof (double)); 42513576Sdlw result_addr = get_operand(sizeof (double)); 42613576Sdlw result_type = DOUBLE; 42713576Sdlw break; 42813576Sdlw 42913576Sdlw case ADDF3: 43013576Sdlw case DIVF3: 43113576Sdlw case MULF3: 43213576Sdlw case SUBF3: 43313576Sdlw (void) get_operand(sizeof (float)); 43413576Sdlw /* intentional fall-thru */ 43513576Sdlw 43613576Sdlw case ADDF2: 43713576Sdlw case DIVF2: 43813576Sdlw case MULF2: 43913576Sdlw case SUBF2: 44013576Sdlw case MNEGF: 44113576Sdlw case MOVF: 44213576Sdlw (void) get_operand(sizeof (float)); 44313576Sdlw result_addr = get_operand(sizeof (float)); 44413576Sdlw result_type = FLOAT; 44513576Sdlw break; 44613576Sdlw 44713576Sdlw case CVTDF: 44813576Sdlw (void) get_operand(sizeof (double)); 44913576Sdlw result_addr = get_operand(sizeof (float)); 45013576Sdlw result_type = FLOAT; 45113576Sdlw break; 45213576Sdlw 45313576Sdlw case CVTFD: 45413576Sdlw (void) get_operand(sizeof (float)); 45513576Sdlw result_addr = get_operand(sizeof (double)); 45613576Sdlw result_type = DOUBLE; 45713576Sdlw break; 45813576Sdlw 45913576Sdlw case EMODF: 46013576Sdlw case EMODD: 46113576Sdlw fprintf(ef, "trpfpe: can't fix emod yet\n"); 46213576Sdlw goto cant_fix; 46313576Sdlw 46413576Sdlw case POLYF: 46513576Sdlw case POLYD: 46613576Sdlw fprintf(ef, "trpfpe: can't fix poly yet\n"); 46713576Sdlw goto cant_fix; 46813576Sdlw 46913576Sdlw case ACBD: 47013576Sdlw case ACBF: 47113576Sdlw case CMPD: 47213576Sdlw case CMPF: 47313576Sdlw case TSTD: 47413576Sdlw case TSTF: 47513576Sdlw case CVTDB: 47613576Sdlw case CVTDL: 47713576Sdlw case CVTDW: 47813576Sdlw case CVTFB: 47913576Sdlw case CVTFL: 48013576Sdlw case CVTFW: 48113576Sdlw case CVTRDL: 48213576Sdlw case CVTRFL: 48313576Sdlw /* These can generate only reserved operand faults */ 48413576Sdlw /* They are shown here for completeness */ 48513576Sdlw 48613576Sdlw default: 48713576Sdlw fprintf(stderr, "trp: opcode 0x%02x unknown\n", 48813576Sdlw *(--(*ipc)) & 0xff); 48913576Sdlw goto cant_fix; 49013576Sdlw /* NOTREACHED */ 49113576Sdlw } 49213576Sdlw 49313576Sdlw if (result_type == FLOAT) 49413576Sdlw result_addr->ua_float = retval.rv_float; 49513576Sdlw else 49613576Sdlw { 49713576Sdlw if (result_addr == (anything *)&iR6) 49813576Sdlw { /* 49913576Sdlw * special case - the R6/R7 pair is stored apart 50013576Sdlw */ 50113576Sdlw result_addr->ua_long = retval.rv_long[0]; 50213576Sdlw ((anything *)&iR7)->ua_long = retval.rv_long[1]; 50313576Sdlw } 50413576Sdlw else 50513576Sdlw result_addr->ua_double = retval.rv_double; 50613576Sdlw } 50713576Sdlw signal(SIGFPE, on_fpe); 50813576Sdlw } 50913576Sdlw #endif vax 51013576Sdlw 51113576Sdlw trpfpe_ (count, rval) 51213576Sdlw long *count; /* how many to announce */ 51313576Sdlw double *rval; /* dummy return value */ 51413576Sdlw { 51513576Sdlw #if vax 51613576Sdlw max_messages = *count; 51713576Sdlw retval.rv_double = *rval; 51813576Sdlw sigfpe_dfl = signal(SIGFPE, on_fpe); 51913576Sdlw fpe_count = 0; 52013576Sdlw #endif 52113576Sdlw } 52213576Sdlw 52313576Sdlw long 52413576Sdlw fpecnt_ () 52513576Sdlw { 52613576Sdlw #if vax 52713576Sdlw return (fpe_count); 52813576Sdlw #else 52913576Sdlw return (0L); 53013576Sdlw #endif 53113576Sdlw } 53213576Sdlw 533