/***** * * Michael Riff * Object software version 1.0 Okto 2013. * * This file contains an implementation of some standard IO and library routines of unix. * The standard IO routines use the lower part of a MacOS window (to left corner passed to InitStdio} as a console. * The file IO routie just map the unix routine the MacOS calls. * If USE_FORMATX2STR is defined the conversion from float values to string is done using FormatX2Str routine. * As the conversion did not work properly I implmeented a conversion without. At last I found out tat the format string * passed to Str2Format must not contain any blancs. * * Version 1.1: 04 Feb 2014 * Renamed InitStdLib * * Version 1.2: 08 Feb 2014 * Added error checking for calls to Formatx2Str and FomatStr2X. Additionally check if input string contains * the decimal separator character before calling FormatStr2X. If not conversion done with String2Num. * Floating point conversion routines uses decimal separator from itl resource if USE_ITL is defined. * Added alternative code to FormatStr2X used if USE_FORMATX2STR is not defined. * Corrected little error in exponent handling for %e format of routine sscanf. * Prepared replacement of long double to ext 80 and back conversion routines by double to ext 80 and back. * * Version 1.3: 11 Aug 2014 * Correction in handling of formats %n.mg for cases when values as 9_9.9999 have to be rounded up. * * Version 1.5: 28 Sept 2014 * Correction and optimisation in handling of formats %s in printf routine. * * Version 1.6: 06 June 2016 * Adaptations to compile the code with CodeWarrior and suppress warnings. * USE_FORMATX2STR version: copy parts table into non relocatable memory (as used later). * * Version 1.7: 23 July 2016 * Pb when enabling code optimizer with Symantec C++: * The code checking for NAN or INF values in printf for the case %f is thrown away! * To solve this problem, the optimizer is switched off for the printf routine with #pragmas * Suppressed unused variable in scanf. * 30 July 2016 * Same problem noticed in handling the - sign in atof routine. * Error correction in printf routine: * suppressed code for %f case as when a float value is passed as parameter, a double value * is put onto the argument stack. So use same code as for %g. * *****/ #include typedef unsigned long size_t; Ptr malloc(size_t taille) { return NewPtr(taille); } void free(void *ptr) { DisposPtr((Ptr)ptr); } Ptr calloc(size_t typeSize, size_t num) { return NewPtrClear(typeSize * num); } void memcpy(void* to, const void* from, size_t size) { BlockMove(from, to, size); } #include typedef struct { FSSpec spec; short fRefNum; short vRefNum; Boolean EOF; } FILE; OSErr erreur; FILE *fopen(const char *filename, const char *mode) { FILE *MacFile; Str255 fName; int length = -1; MacFile = (FILE*)NewPtr(sizeof(FILE)); GetVol(NULL, &(MacFile->vRefNum)); while (filename[++length]); BlockMove(filename,fName+1, length); fName[0] = length; erreur = FSMakeFSSpec(MacFile->vRefNum, 0, fName, &(MacFile->spec)); if (erreur) { return NULL; } else { erreur = FSOpen(fName, MacFile->vRefNum, &(MacFile->fRefNum)); if (erreur) { return NULL; } else { MacFile->EOF = false; return MacFile; } } } // For PBRead #include char * fgets(char *s, int n, FILE *stream) { // long count = n; ParamBlockRec data; if (stream->EOF) { s[0] = 0; return NULL; } /* erreur = FSRead(stream->fRefNum, &count, (Ptr)s); if (eofErr == erreur) { stream->EOF = true; s[count] = 0; } else if (erreur) { s[0] = 0; } else { s[count] = 0; } return s; */ data.ioParam.ioRefNum = stream->fRefNum; // data.ioParam.ioVersNum = ; data.ioParam.ioPermssn = fsRdPerm; // data.ioParam.ioMisc =; data.ioParam.ioBuffer = s; data.ioParam.ioReqCount = n-1; // data.ioParam.ioActCount; data.ioParam.ioPosMode = ('\r'<<8) | 0x0080; // data.ioParam.ioPosMode = ('\n'<<8) | 0x0080; data.ioParam.ioPosOffset = 0; // ignored erreur = PBRead(&data, 0); if (eofErr == erreur) { stream->EOF = true; s[data.ioParam.ioActCount] = 0; } else if (erreur) { s[0] = 0; } else { s[data.ioParam.ioActCount] = 0; } return s; } void fclose(FILE *file) { FSClose(file->fRefNum); DisposePtr((Ptr)file); } #include #include #include FontInfo fonte; short htrLigne; WindowPtr StdOut; Point HautGche; Rect ConsolRect; // For scrolling when the bottom of console window is reached RgnHandle UpdateRgn; // To keep position of the console where the next text will be written // in case something will be written elsewhere inbetween. Point cursPos; // To store oroginal position of cursor when selecting the console // so to return to this position when quitting the console. Point macPos; const char iTox[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',\ 'A', 'B', 'C', 'D', 'E', 'F' }; #include #ifdef USE_FORMATX2STR long partsOffset; long partsLength; Itl4Handle interRess; NumberParts *partsTbl = NULL; Str255 formatDefE = "\p############.########;-############.########;0.0"; Str255 formatDefF = "\p#######.###;-#######.###;0.0"; Str255 formatDefD = "\p#########.#####;-#########.#####;0.0"; NumFormatString formatRecE, formatRecF, formatRecD; #else // Only because they are used in Display.c long partsOffset; long partsLength; Itl4Handle interRess; NumberParts *partsTbl = NULL; Str255 formatDefF = "\p#######.###;-#######.###;0.0"; NumFormatString formatRecF; #endif #define NUM_DEC_E 8 #define NUM_DEC_F 3 #define NUM_DEC_D 5 double Precis_E; double Precis_F; double Precis_D; const char dec2Ascii[10] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; #ifdef USE_ITL /* For proper internationalization get decimal separator from system settings Two ways to get it: - from itl0 resource - from international table referenced in itl4 resource that has to be loaded anyway when using Str2Format/FormatStr2X/FormatX2Str */ char decSeparat; /* Handle to itl0 resource */ #ifndef USE_FORMATX2STR #include Handle hitlbData; #endif Handle hitl0Data; #endif /* For handling of NAN and INF cases in printf */ #ifdef Mac #include #endif #ifdef __MWERKS__ /* Copied here from from Symantec C++ as it is not defined in CodeWarrior. */ struct Int64Bit { SInt32 hiLong; UInt32 loLong; }; typedef struct Int64Bit Int64Bit; #endif typedef union { double value; #ifndef Mac unsigned int raw[2]; #else Int64Bit raw; #endif } dbl_raw_type; #ifdef __SC__ // Pb: if global optimiser is on, the symantec compiler suppresses the complete check for NAN or INF values // in the case printf %f (%g is OK) dbl_raw_type dblRawConvInf; #else dbl_raw_type dblRawConvInf; #endif #ifndef Mac #define CHECKNANINF(value) check = (dbl_raw_type*)&value; \ if (0x7FF00000 == (check->raw[0] & 0x7FF00000)) { \ if (0 != (0x000FFFFFF && check->raw[0]) || 0 != check->raw[1]) { \ out[idxOut] = 'N'; out[idxOut+1] = 'A'; out[idxOut+2] = 'N'; \ } else { \ out[idxOut] = 'I'; out[idxOut+1] = 'N'; out[idxOut+2] = 'F'; \ } \ idxOut += 3; \ } else { #else #define CHECKNANINF(value) check = (dbl_raw_type*)&value; \ if (0x7FF00000 == (check->raw.hiLong & 0x7FF00000)) { \ if (0 != (0x000FFFFFF && check->raw.hiLong) || 0 != check->raw.loLong) { \ out[idxOut] = 'N'; out[idxOut+1] = 'A'; out[idxOut+2] = 'N'; \ } else { \ out[idxOut] = 'I'; out[idxOut+1] = 'N'; out[idxOut+2] = 'F'; \ } \ idxOut += 3; \ } else { #endif typedef union { float value; unsigned int raw; } flt_raw_type; void InitStdio(WindowPtr port, Point startPos) { int idx; SetPort((GrafPtr)port); StdOut = port; GetFontInfo(&fonte); htrLigne = fonte.ascent + fonte.descent + fonte.leading; HautGche = startPos; ConsolRect.left = startPos.h; ConsolRect.top = startPos.v; ConsolRect.bottom = ((GrafPtr)port)->portRect.bottom; ConsolRect.right = ((GrafPtr)port)->portRect.right; UpdateRgn = NewRgn(); // DisposeRgn(UpdateRgn) à faire !!! #ifndef USE_FORMATX2STR #ifdef USE_ITL if (0 == decSeparat) { // hitlbData = GetResource('itlb', 0); // hitl0Data = GetResource('itl0', ((ItlbRecord*)(*hitlbData))->itlbNumber); hitl0Data = IUGetIntl(0); /* don't use GetResource */ decSeparat = (*(Intl0Hndl)hitl0Data)->decimalPt; } // Only because they are used in Display.c if ('.' != decSeparat) { for(idx=1; idx<=formatDefF[0]; idx++) { if ('.' == formatDefF[idx]) { formatDefF[idx] = decSeparat; } } } #endif // Only because they are used in Display.c if (!partsTbl) { IUGetItlTable(iuSystemScript, iuNumberPartsTable, (Handle*)(&interRess), &partsOffset, &partsLength); HLock((Handle)interRess); partsTbl = (NumberPartsPtr)NewPtr(partsLength); LoadResource((Handle)interRess); BlockMove((Ptr)(*interRess) + partsOffset, partsTbl, partsLength); HUnlock((Handle)interRess); } erreur = Str2Format(formatDefF, partsTbl, &formatRecF); if (erreur) { ParamText("\pFloat num formatF","\perreur",NULL,NULL); StopAlert(128, NULL); } #else if (!partsTbl) { IUGetItlTable(iuSystemScript, iuNumberPartsTable, (Handle*)(&interRess), &partsOffset, &partsLength); HLock((Handle)interRess); partsTbl = (NumberPartsPtr)NewPtr(partsLength); LoadResource((Handle)interRess); BlockMove((Ptr)(*interRess) + partsOffset, partsTbl, partsLength); HUnlock((Handle)interRess); } #ifdef USE_ITL if (0 == decSeparat) { // decSeparat = (partsTbl->data[tokDecPoint]).a[1]; is not portable. Does not work with CW 6.0 hitl0Data = IUGetIntl(0); /* don't use GetResource */ decSeparat = (*(Intl0Hndl)hitl0Data)->decimalPt; } if ('.' != decSeparat) { for(idx=1; idx<=formatDefE[0]; idx++) { if ('.' == formatDefE[idx]) { formatDefE[idx] = decSeparat; } } for(idx=1; idx<=formatDefF[0]; idx++) { if ('.' == formatDefF[idx]) { formatDefF[idx] = decSeparat; } } for(idx=1; idx<=formatDefD[0]; idx++) { if ('.' == formatDefD[idx]) { formatDefD[idx] = decSeparat; } } } #endif erreur = Str2Format(formatDefE, partsTbl, &formatRecE); if (erreur) { ParamText("\pFloat num formatE","\perreur",NULL,NULL); StopAlert(128, NULL); } erreur = Str2Format(formatDefF, partsTbl, &formatRecF); if (erreur) { ParamText("\pFloat num formatF","\perreur",NULL,NULL); StopAlert(128, NULL); } erreur = Str2Format(formatDefD, partsTbl, &formatRecD); if (erreur) { ParamText("\pFloat num formatD","\perreur",NULL,NULL); StopAlert(128, NULL); } #endif Precis_E = pow(10,NUM_DEC_E); Precis_F = pow(10,NUM_DEC_F); Precis_D = pow(10,NUM_DEC_D); MoveTo(startPos.h, startPos.v +htrLigne); cursPos.h = startPos.h; cursPos.v = startPos.v +htrLigne; macPos.h = (port->pnLoc).h; macPos.v = (port->pnLoc).v; #ifndef Mac dblRawConvInf.raw[0] = 0x7FF00000; dblRawConvInf.raw[1] = 0x00000000; #else dblRawConvInf.raw.hiLong = (SInt32)0x7FF00000; dblRawConvInf.raw.loLong = 0x00000000; #endif } void SelectConsole() { if (StdOut != FrontWindow()) { SelectWindow(StdOut); } SetPort(StdOut); macPos.h = (StdOut->pnLoc).h; macPos.v = (StdOut->pnLoc).v; MoveTo(cursPos.h, cursPos.v); } void DeselectConsole() { MoveTo(macPos.h, macPos.v); } void ReleaseConsole() { DisposeRgn(UpdateRgn); DisposPtr((Ptr)partsTbl); } #if defined(__SC__) && __option(global_optimizer) #define SC_OPTIMIZE #pragma SC options(!global_optimizer) #pragma message "SC optim SOff" #endif int printf(const char *format, ...) { int idx, idxOut, exp, idxTmp; va_list pile; Str255 out; Str63 tmp; char cBuf, *sBuf; long lgBuf; int lIdx; int coefd; // double tmpDbl; Boolean partieFrac; unsigned char numMant; unsigned char numFrac; int loop; double dblBuf; dbl_raw_type *check; #ifdef USE_FORMATX2STR long double ldblVal; extended80 xValue; #endif va_start(pile ,format); idx = 0; idxOut = 1; while(format[idx]){ if ('%'!=format[idx] && '\n'!=format[idx] && '\r'!=format[idx]) { out[idxOut++] = format[idx]; } else { if('\r' == format[idx]) { out[0] = idxOut-1; DrawString(out); idxOut = 1; out[0] = 0; MoveTo(ConsolRect.left,(((GrafPtr)StdOut)->pnLoc).v); } else if('\n' == format[idx]) { out[0] = idxOut-1; DrawString(out); idxOut = 1; out[0] = 0; if ((StdOut->pnLoc).v > StdOut->portRect.bottom-htrLigne) { ScrollRect(&ConsolRect, 0 , -htrLigne, UpdateRgn); MoveTo(ConsolRect.left,(((GrafPtr)StdOut)->pnLoc).v); } else { // For RPN // Move(0, htrLigne); MoveTo(ConsolRect.left,(((GrafPtr)StdOut)->pnLoc).v+htrLigne); } } else { switch(format[++idx]) { // Switch 1 case 'c': // cBuf = va_arg(pile, char); gibt immer 0 cBuf = va_arg(pile, int); out[idxOut++] = cBuf; break; case 's': sBuf = va_arg(pile, char*); for(idxTmp = -1; idxTmp<100 && sBuf[++idxTmp]; ); // Limit to 100 for safe solution BlockMove(sBuf, out+idxOut, idxTmp); idxOut += idxTmp; break; case 'd': lgBuf = va_arg(pile, long); NumToString(lgBuf, tmp); BlockMove(tmp+1, out+idxOut, tmp[0]); idxOut += tmp[0]; break; case 'x': lgBuf = va_arg(pile, long); out[idxOut++] = iTox[0x00000000F & (lgBuf>>28)]; out[idxOut++] = iTox[0x00000000F & (lgBuf>>24)]; out[idxOut++] = iTox[0x00000000F & (lgBuf>>20)]; out[idxOut++] = iTox[0x00000000F & (lgBuf>>16)]; out[idxOut++] = iTox[0x00000000F & (lgBuf>>12)]; out[idxOut++] = iTox[0x00000000F & (lgBuf>>8)]; out[idxOut++] = iTox[0x00000000F & (lgBuf>>4)]; out[idxOut++] = iTox[0x00000000F & lgBuf]; break; case 'e': //Debugger(); dblBuf = va_arg(pile, double); exp = (int)floor(log(dblBuf)/log(10)); dblBuf /= pow(10,exp); #ifdef USE_FORMATX2STR // Round value to fit predefined format string dblBuf = (dblBuf*Precis_E - floor(dblBuf*Precis_E))>0.5 ? ceil(dblBuf*Precis_E) / Precis_E : floor(dblBuf*Precis_E) / Precis_E; ldblVal = (long double)dblBuf; ldtox80 ( &ldblVal, &xValue ); // dtox80 ( &dblBuf, &xValue ); tmp[0] = 0; erreur = FormatX2Str(&xValue, &formatRecE, partsTbl, tmp); if (erreur) { ParamText("\pPrintf","\pFormatX2Str","\p%e","\perror"); StopAlert(128, NULL); tmp[0] = 0; break; } #else idxTmp = 1; if (0>dblBuf) { tmp[idxTmp++] = '-'; dblBuf = -dblBuf; } exp = (int)floor(log10(dblBuf)); // size_IP = exp+1; // Convert integer part if ( 0<=exp ) { // dlbBuf >= 1.0 for (lIdx=exp; lIdx>=0; lIdx--) { coefd = floor(dblBuf / pow(10,lIdx)); dblBuf -= coefd*pow(10,lIdx); tmp[idxTmp++] = dec2Ascii[coefd]; } // Safety check if (dblBuf >= 1.0) { // Pb Debugger(); tmp[0] = idxTmp-1; } } else { // dlbBuf < 1.0 tmp[idxTmp++] = '0'; } #ifndef USE_ITL tmp[idxTmp++] = '.'; #else tmp[idxTmp++] = decSeparat; #endif // Convert fractionnary part lIdx = 1; while( pow(10,exp-10) < dblBuf ) { coefd = floor(dblBuf * pow(10, lIdx)); dblBuf -= coefd/pow(10,lIdx); tmp[idxTmp++] = dec2Ascii[coefd]; lIdx++; } tmp[0] = idxTmp-1; #endif BlockMove(tmp+1, out+idxOut, tmp[0]); idxOut += tmp[0]; out[idxOut++] = 'e'; NumToString(exp,tmp); BlockMove(tmp+1, out+idxOut, tmp[0]); idxOut += tmp[0]; break; case 'f': case 'g': //Debugger(); dblBuf = va_arg(pile, double); CHECKNANINF(dblBuf) #ifdef USE_FORMATX2STR // Round value to fit predefined format string dblBuf = (dblBuf*Precis_D - floor(dblBuf*Precis_D))>0.5 ? ceil(dblBuf*Precis_D) / Precis_D : floor(dblBuf*Precis_D) / Precis_D; ldblVal = (long double)dblBuf; ldtox80 ( &ldblVal, &xValue ); // dtox80 ( &dblBuf, &xValue ); tmp[0] = 0; erreur = FormatX2Str(&xValue, &formatRecD, partsTbl, tmp); if (erreur) { ParamText("\pPrintf","\pFormatX2Str","\p%g","\perror"); StopAlert(128, NULL); tmp[0] = 0; break; } #else idxTmp = 1; if (0>dblBuf) { tmp[idxTmp++] = '-'; dblBuf = -dblBuf; } exp = (int)floor(log10(dblBuf)); // size_IP = exp+1; // Convert integer part if ( 0<=exp ) { // dlbBuf >= 1.0 for (lIdx=exp; lIdx>=0; lIdx--) { coefd = floor(dblBuf / pow(10,lIdx)); dblBuf -= coefd*pow(10,lIdx); tmp[idxTmp++] = dec2Ascii[coefd]; } // Safety check if (dblBuf >= 1.0) { // Pb Debugger(); tmp[0] = idxTmp-1; } } else { // dlbBuf < 1.0 tmp[idxTmp++] = '0'; } #ifndef USE_ITL tmp[idxTmp++] = '.'; #else tmp[idxTmp++] = decSeparat; #endif // Convert fractionnary part lIdx = 1; while(pow(10,exp-10) < dblBuf) { coefd = floor(dblBuf * pow(10, lIdx)); dblBuf -= coefd/pow(10,lIdx); tmp[idxTmp++] = dec2Ascii[coefd]; lIdx++; } tmp[0] = idxTmp-1; #endif BlockMove(tmp+1, out+idxOut, tmp[0]); idxOut += tmp[0]; } break; case 'l': if ('d' != format[++idx]) { // Pb lgBuf = 0; } else { /* ou interpreter values comme Int64Bit Int64Bit i64Buf; i64Buf = va_arg(pile, Int64Bit); i64Buf.hiLong = i64Buf.loLong = */ lgBuf = va_arg(pile, long); /* dblBuf = (double) lgBuf; exp = (int)floor(log10(dblBuf));// num digits = exp+1 idxTmp = 62; tmpDbl = 10.0; // Do conversion by hand for (lIdx=0; lIdxdblBuf) { tmp[idxTmp++] = '-'; dblBuf = -dblBuf; } exp = (int)floor(log10(dblBuf)); // size_IP = exp+1; // Convert integer part if ( 0<=exp ) { /*if (numMant-exp-1 < 1)*/ tmp[idxTmp++]='0'; // for case 99_99.9999 is to be rounded, keep a place for the additional chiffre. If it remains 0, it will be suppressed //For better performance done systématically // dlbBuf >= 1.0 for(loop=0; loop=0; lIdx--) { coefd = floor(dblBuf / pow(10,lIdx)); dblBuf -= coefd*pow(10,lIdx); tmp[idxTmp++] = dec2Ascii[coefd]; } // Safety check if (dblBuf >= 1.0) { // Pb Debugger(); tmp[0] = idxTmp-1; } } else { /*if (numMant < 1)*/ tmp[idxTmp++]='0'; // for values as .99999 to be rounded // dlbBuf < 1.0 for(loop=0; loop=5) { if (dblBuf*pow(10,lIdx) >= 5) { //Debugger(); lIdx = idxTmp-1; #ifndef USE_ITL while ( tmp[lIdx]=='9' || tmp[lIdx]=='.' ) { // && lIdx>1 #else while ( tmp[lIdx]=='9' || tmp[lIdx]==decSeparat ) { #endif if( tmp[lIdx]=='9' ) {tmp[lIdx] = '0';} lIdx--; } tmp[lIdx] += 1; } } tmp[0] = idxTmp-1; /*if (exp<0 && numMant<1 || exp>=0 && numMant-exp-1<1) { // Suppress additional 0 added at the beginning*/ if (tmp[1]=='-' && tmp[2]=='0') { out[idxOut++] = '-'; BlockMove(tmp+3, out+idxOut, tmp[0]-2); idxOut += tmp[0]-2; } else if (tmp[1]=='0'){ BlockMove(tmp+2, out+idxOut, tmp[0]-1); idxOut += tmp[0]-1; } else { BlockMove(tmp+1, out+idxOut, tmp[0]); idxOut += tmp[0]; } /*} else { BlockMove(tmp+1, out+idxOut, tmp[0]); idxOut += tmp[0]; } */ break; } // End switch 1 } } ++idx; } // va_end(pile); if (idxOut) { out[0] = idxOut-1; DrawString(out); } // Store cursor position for next cursPos.h = (((GrafPtr)StdOut)->pnLoc).h; cursPos.v = (((GrafPtr)StdOut)->pnLoc).v; return idxOut; } #ifdef SC_OPTIMIZE #undef SC_OPTIMIZE #pragma SC options(global_optimizer) #pragma message "SC optim SOn" #endif int sprintf(char *s, const char *format, ...) { int idx, idxOut, exp, idxTmp; va_list pile; Str63 tmp; char cBuf, *sBuf; long lgBuf; double dblBuf; float fltBuf; #ifdef USE_FORMATX2STR long double ldblVal; extended80 xValue; #else int lIdx; int coefd; #endif double tmpDbl; Boolean partieFrac; unsigned char numMant; unsigned char numFrac; int loop; va_start(pile ,format); idx = 0; idxOut = 1; printf("sprintf not implemented!\n"); return idxOut; } int scanf(const char*format, ...) { int idx; va_list pile; Boolean quitter = false; #ifdef USE_FORMATX2STR extended80 xValue; long double ldValue; Boolean decSepPresent; #else Boolean chgSgn; double buf; #endif char *cBuf, *sBuf; long *lgBuf; double *dblBuf; float *fltBuf; long exp; Str63 tmp; char touche; /* Pas *touche sinon pb */ Str255 texte; int idxIn, idxTmp; EventRecord Evt; if ('%' != format[0]) { // Not implemented return 0; } else { MoveTo(ConsolRect.left,(((GrafPtr)StdOut)->pnLoc).v); /* Traitement des touches frappées */ FlushEvents(everyEvent,0); idxIn = 0; while(!quitter) { if ( WaitNextEvent(0xFFFF,&Evt,0x00000080,0L)) { switch(Evt.what) { case nullEvent : break; case mouseUp : break; case mouseDown : quitter = true; break; case keyUp : break; case keyDown : touche = Evt.message & charCodeMask; /* Si *touche plantage ici sauf parfois */ if (touche == '\r' || touche == '\n') { /* si boucle for(;;) au lieu de while() */ texte[idxIn] = 0; quitter = true; } else { texte[idxIn++] = touche; DrawChar(touche); } break; } } } va_start(pile, format); //Debugger(); switch(format[1]) { case 'c': cBuf = va_arg(pile, char*); *cBuf = texte[0]; break; case 's': sBuf = va_arg(pile, char*); BlockMove(texte, sBuf, idxIn+1); break; case 'd': lgBuf = va_arg(pile, long*); idxTmp = 0; while( idxTmp=texte[idxTmp]) || '-'==texte[idxTmp] ) { tmp[idxTmp+1] = texte[idxTmp]; idxTmp++; } tmp[0] = idxTmp; StringToNum(tmp, lgBuf); break; case 'x': lgBuf = va_arg(pile, long*); *lgBuf = 0; idxTmp = 0; while ( idxTmp=texte[idxTmp] || 'A'<=texte[idxTmp] && 'F'>=texte[idxTmp]) ) { *lgBuf *=10; if (texte[idxTmp] < 9) *lgBuf += texte[idxTmp]-'0'; else *lgBuf += texte[idxTmp]-'A'+10; ++idxTmp; } break; case 'e': dblBuf = va_arg(pile, double*); #ifdef USE_FORMATX2STR idx = 1; idxTmp = 0; decSepPresent = false; #ifndef USE_ITL while( idxTmp=texte[idxTmp]) || '.'==texte[idxTmp] || '-'==texte[idxTmp]) ) { if ('.'==texte[idxTmp]) #else while( idxTmp=texte[idxTmp]) || decSeparat==texte[idxTmp] || '-'==texte[idxTmp]) ) { if (decSeparat==texte[idxTmp]) #endif decSepPresent = true; tmp[idx] = texte[idxTmp]; ++idxTmp; ++idx;} tmp[0] = idx-1; if (decSepPresent) { // If decimal separator is missing, returns 1 as error status erreur = FormatStr2X(tmp, &formatRecD, partsTbl, &xValue); if (erreur) { ParamText("\pScanf","\pFormatStr2X",tmp,"\p%e error"); StopAlert(128, NULL); *dblBuf = 0; break; } x80told ( &xValue, &ldValue ); *dblBuf = (double)ldValue; // dValue = x80tod ( &xValue ); // *dblBuf = dValue; } else { // Just convert the integer value StringToNum(tmp, &exp); *dblBuf = (double)exp; } #else idx = 0; idxTmp = 0; *dblBuf=0; if ( '-' == texte[idxTmp] ) { chgSgn = true; ++idxTmp; } else { chgSgn = false; } #ifndef USE_ITL while( idxTmp=texte[idxTmp]) && '.'!=texte[idxTmp]) ) // idxTmp=texte[idxTmp]) && decSeparat!=texte[idxTmp]) ) #endif { *dblBuf = (*dblBuf)*10 + texte[idxTmp]-48; ++idxTmp; } #ifndef USE_ITL if ('.'==texte[idxTmp]) ++idxTmp; #else if (decSeparat==texte[idxTmp]) ++idxTmp; #endif buf = 0.1; while(idxTmp=texte[idxTmp]) || '-'==texte[idxTmp]) ) { tmp[idx++] = texte[idxTmp++]; } tmp[0] = idx-1; StringToNum(tmp, &exp); *dblBuf *= pow(10, exp); } break; case 'f': fltBuf = va_arg(pile, float*); #ifdef USE_FORMATX2STR idxTmp = 0; decSepPresent = false; #ifndef USE_ITL while( idxTmp=texte[idxTmp]) || '.'==texte[idxTmp] || '-'==texte[idxTmp]) ) { if ('.'==texte[idxTmp]) #else while( idxTmp=texte[idxTmp]) || decSeparat==texte[idxTmp] || '-'==texte[idxTmp]) ) { if (decSeparat==texte[idxTmp]) #endif decSepPresent = true; tmp[idxTmp+1] = texte[idxTmp]; ++idxTmp; } tmp[0] = idxTmp; if (decSepPresent) { // If decimal separator is missing, returns 1 as error status erreur = FormatStr2X(tmp, &formatRecD, partsTbl, &xValue); if (erreur) { ParamText("\pScanf","\pFormatStr2X %f",tmp,"\perror"); StopAlert(128, NULL); *fltBuf = 0; break; } x80told ( &xValue, &ldValue ); *fltBuf = (float)ldValue; // dValue = x80tod ( &xValue ); // *fltBuf = (float)dValue; } else { // Just convert the integer value StringToNum(tmp, &exp); *fltBuf = (double)exp; } #else idx = 0; *fltBuf=0; if ('-' == texte[idx]) { chgSgn = true; ++idx; } else { chgSgn = false; } #ifndef USE_ITL while( idx=texte[idx]) && '.'!=texte[idx]) ) // idx=texte[idx]) && decSeparat!=texte[idx]) ) #endif { *fltBuf = (*fltBuf)*10 + texte[idx]-48; ++idx; } #ifndef USE_ITL if ('.'==texte[idx]) ++idx; #else if (decSeparat==texte[idx]) ++idx; #endif buf = 0.1; while( idx=texte[idxTmp]) || '.'==texte[idxTmp] || '-'==texte[idxTmp]) ) { if ('.'==texte[idxTmp]) #else while( idxTmp=texte[idxTmp]) || decSeparat==texte[idxTmp] || '-'==texte[idxTmp]) ) { if (decSeparat==texte[idxTmp]) #endif decSepPresent = true; tmp[idxTmp+1] = texte[idxTmp]; ++idxTmp; } tmp[0] = idxTmp; if (decSepPresent) { // If decimal separator is missing, returns 1 as error status erreur = FormatStr2X(tmp, &formatRecD, partsTbl, &xValue); if (erreur) { ParamText("\pScanf","\pFormatStr2X %g",tmp,"\perror"); StopAlert(128, NULL); *dblBuf = 0; break; } x80told ( &xValue, &ldValue ); *dblBuf = (double)ldValue; // dValue = x80tod ( &xValue ); // *dblBuf = dValue; } else { // Just convert the integer value StringToNum(tmp, &exp); *dblBuf = (double)exp; } #else idx = 0; *dblBuf=0; if ( '-' == texte[idx] ) { chgSgn = true; ++idx; } else { chgSgn = false; } #ifndef USE_ITL while( idx=texte[idx]) && '.'!=texte[idx]) ) // idx=texte[idx]) && decSeparat!=texte[idx]) ) #endif { *dblBuf = (*dblBuf)*10 + texte[idx]-48; ++idx; } #ifndef USE_ITL if ('.'==texte[idx]) ++idx; #else if (decSeparat==texte[idx]) ++idx; #endif buf = 0.1; while( idx=s[idx]) || '-'==s[idx] ) tmp[idxTmp++] = s[idx++]; tmp[0] = idxTmp-1; StringToNum(tmp, lgBuf); break; case 'x': lgBuf = va_arg(pile, long*); *lgBuf = 0; while ( s[idx] && ('0'<=s[idx] && '9'>=s[idx] || 'A'<=s[idx] && 'F'>=s[idx]) ) { *lgBuf *=10; if (s[idx] < 9) *lgBuf += s[idx]-'0'; else *lgBuf += s[idx]-'A'+10; ++idx; } break; case 'e': dblBuf = va_arg(pile, double*); #ifdef USE_FORMATX2STR idxTmp = 1; decSepPresent = false; #ifndef USE_ITL while( s[idx] && (('0'<=s[idx] && '9'>=s[idx]) || '.'==s[idx] || '-'==s[idx]) ) { if ( '.'==s[idx]) #else while( s[idx] && (('0'<=s[idx] && '9'>=s[idx]) || decSeparat==s[idx] || '-'==s[idx]) ) { if ( decSeparat==s[idx]) #endif decSepPresent = true; tmp[idxTmp++] = s[idx++]; } tmp[0] = idxTmp-1; if (decSepPresent) { // If decimal separator is missing, returns 1 as error status erreur = FormatStr2X(tmp, &formatRecD, partsTbl, &xValue); if (erreur) { ParamText("\pSscanf","\pFormatStr2X %e",tmp,"\perreur"); StopAlert(128, NULL); *dblBuf = 0; break; } x80told ( &xValue, &ldValue ); *dblBuf = (double)ldValue; // *dblBuf = x80tod ( &xValue ); } else { // Just convert the integer value StringToNum(tmp, &exp); *dblBuf = (double)exp; } #else *dblBuf=0; if ('-' == s[idx]) { chgSgn = true; ++idx; } else { chgSgn = false; } #ifndef USE_ITL while( ('0'<=s[idx] && '9'>=s[idx]) && '.'!=s[idx] ) #else while( ('0'<=s[idx] && '9'>=s[idx]) && decSeparat!=s[idx] ) #endif { *dblBuf = (*dblBuf)*10 + s[idx]-48; ++idx; } #ifndef USE_ITL if ('.'==s[idx]) ++idx; #else if (decSeparat==s[idx]) ++idx; #endif buf = 0.1; while( '0'<=s[idx] && '9'>=s[idx] ) { (*dblBuf) += buf*(s[idx]-48); buf /= 10; ++idx; } if (chgSgn) *dblBuf = -(*dblBuf); #endif if (s[idx] == 'e' || s[idx] == 'E') { ++idx; idxTmp = 1; while( s[idx] && (('0'<=s[idx] && '9'>=s[idx]) || '-'==s[idx]) ) tmp[idxTmp++] = s[idx++]; tmp[0] = idxTmp-1; StringToNum(tmp, &exp); *dblBuf *= pow(10, exp); } break; case 'f': fltBuf = va_arg(pile, float*); #ifdef USE_FORMATX2STR idxTmp = 1; decSepPresent = false; #ifndef USE_ITL while( s[idx] && (('0'<=s[idx] && '9'>=s[idx]) || '.'==s[idx] || '-'==s[idx]) ) { if ('.'==s[idx]) #else while( s[idx] && (('0'<=s[idx] && '9'>=s[idx]) || decSeparat==s[idx] || '-'==s[idx]) ) { if (decSeparat==s[idx]) #endif decSepPresent = true; tmp[idxTmp++] = s[idx++]; } tmp[0] = idxTmp-1; if (decSepPresent) { // If decimal separator is missing, returns 1 as error status erreur = FormatStr2X(tmp, &formatRecD, partsTbl, &xValue); if (erreur) { ParamText("\pSscanf","\pFormatStr2X %f",tmp,"\perreur"); StopAlert(128, NULL); *fltBuf = 0; break; } x80told ( &xValue, &ldValue ); *fltBuf = (float)ldValue; // *dblBuf = x80tod ( &xValue ); } else { // Just convert the integer value StringToNum(tmp, &exp); *fltBuf = (float)exp; } #else *fltBuf=0; if ('-' == s[idx]) { chgSgn = true; ++idx; } else { chgSgn = false; } #ifndef USE_ITL while( ('0'<=s[idx] && '9'>=s[idx]) && '.'!=s[idx] ) #else while( ('0'<=s[idx] && '9'>=s[idx]) && decSeparat!=s[idx] ) #endif { *fltBuf = (*fltBuf)*10 + s[idx]-48; ++idx; } #ifndef USE_ITL if ('.'==s[idx]) ++idx; #else if (decSeparat==s[idx]) ++idx; #endif buf = 0.1; while( '0'<=s[idx] && '9'>=s[idx] ) { (*fltBuf) += buf*(s[idx]-48); buf /= 10; ++idx; } if (chgSgn) *fltBuf = -(*fltBuf); #endif break; case 'g': dblBuf = va_arg(pile, double*); #ifdef USE_FORMATX2STR idxTmp = 1; decSepPresent = false; #ifndef USE_ITL while( s[idx] && (('0'<=s[idx] && '9'>=s[idx]) || '.'==s[idx] || '-'==s[idx]) ) { if ( '.'==s[idx] ) #else while( s[idx] && (('0'<=s[idx] && '9'>=s[idx]) || decSeparat==s[idx] || '-'==s[idx]) ) { if ( decSeparat==s[idx] ) #endif decSepPresent = true; tmp[idxTmp++] = s[idx++]; } tmp[0] = idxTmp-1; if (decSepPresent) { // If decimal separator is missing, returns 1 as error status erreur = FormatStr2X(tmp, &formatRecD, partsTbl, &xValue); if (erreur) { ParamText("\pSscanf","\pFormatStr2X %g",tmp,"\perreur"); StopAlert(128, NULL); *dblBuf = 0; break; } x80told ( &xValue, &ldValue ); *dblBuf = (double)ldValue; // *dblBuf = x80tod ( &xValue ); } else { // Just convert the integer value StringToNum(tmp, &exp); *dblBuf = (double)exp; } #else *dblBuf=0; if ('-' == s[idx]) { chgSgn = true; ++idx; } else { chgSgn = false; } #ifndef USE_ITL while( ('0'<=s[idx] && '9'>=s[idx]) && '.'!=s[idx] ) #else while( ('0'<=s[idx] && '9'>=s[idx]) && decSeparat!=s[idx] ) #endif { *dblBuf = (*dblBuf)*10 + s[idx]-48; ++idx; } #ifndef USE_ITL if ('.'==s[idx]) ++idx; #else if (decSeparat==s[idx]) ++idx; #endif buf = 0.1; while( '0'<=s[idx] && '9'>=s[idx] ) { (*dblBuf) += buf*(s[idx]-48); buf /= 10; ++idx; } if (chgSgn) *dblBuf = -(*dblBuf); #endif break; default: Debugger(); } } ++idxF; } va_end(pile); return idxF; // TBC } int strlen(const char *s) { int lgth=-1; while(0 != *(s + (++lgth))); return lgth; } int strcmp(const char *s1, const char *s2) { int idx; idx=-1; do { ++idx; } while (s1[idx] && s2[idx] && s1[idx]==s2[idx]); if (!s1[idx]) { if (!s2[idx]) { return 0; } else { return 1; } } else { if (!s2[idx]) { return -1; } else { if (s1[idx] long atoi(Ptr sValue) { long result; int idx; // Suppress characters that are not part of number idx = 0; while (sValue[idx]>='0' && sValue[idx]<='9') idx++; sValue[idx] = 0; c2pstr(sValue); StringToNum((unsigned char*)sValue, &result); p2cstr((unsigned char*)sValue); return result; } /* Table ASCII '0' - '9' 48 - 57 'a' - 'f' 97 - 102 'a' - 'z' 97 - 122 'A' - 'F' 65 - 70 'A' - 'Z' 65 - 90 */ long int strtol(const char *str, char **endptr, int base) { int idx; Boolean stop; long int result; int sign; // Check valid base if (base !=0 && (base) <2 || base > 36) { if (endptr) *endptr = (char*)str; return 0; } // Check for sign idx = 0; if ('-' == str[idx] ) { sign = -1; idx++; } if (0==base) { // Determine base with 2 first chars if ('0' == str[0]) { if ('1'<= str[0] && '7' >= str[0] ) base = 8; if ('x' == str[1] ||'X' == str[1] ) base = 16; } else if ('1'<= str[0] && '9' >= str[0] ) { base = 10; } } result = 0; stop = false; if (base <= 10) { do { if ('0'<=str[idx] && '9'>=str[idx]) { // ou base+47>= result *= base; result += str[idx] - '0'; } else { stop = true; if (endptr) *endptr = (char*)(str+idx); } idx++; } while (!stop); } else if (base <= 16) { do { if ('0'<=str[idx] && '9'>=str[idx]) { result *= base; result += str[idx] - '0'; } else if ('a'<=str[idx] && 'f'>=str[idx]) { // base-10+96>= result *= base; result +=str[idx]-'a'+10; } else if ('A'<=str[idx] && 'F'>=str[idx]) { // base-10+64>= result *= base; result +=str[idx]-'A'+10; } else { stop = true; if (endptr) *endptr = (char*)(str+idx); } idx++; } while (!stop); } else { do { if ('0'<=str[idx] && '9'>=str[idx]) { result *= base; result += str[idx] - '0'; } else if ('a'<=str[idx] && 'z'>=str[idx]) { // base-10+96>= result *= base; result +=str[idx]-'a'+10; } else if ('A'<=str[idx] && 'Z'>=str[idx]) { // base-10+64>= result *= base; result +=str[idx]-'A'+10; } else { stop = true; if (endptr) *endptr = (char*)(str+idx); } idx++; } while (!stop); } return result*sign; } unsigned long int strtoul(const char *str, char **endptr, int base) { int idx; Boolean stop; long int result; int sign; // Check valid base if (base !=0 && (base) <2 || base > 36) { if (endptr) *endptr = (char*)str; return 0; } // Check for sign if ('-' == str[0] ) { if (endptr) *endptr = (char*)str; return 0; } printf("strtoul to be implemented\n"); return 0; } /* Defined previously long partsOffset; long partsLength; Itl4Handle interRess; NumberParts *partsTbl; */ #ifdef USE_FORMATX2STR Str255 formatDefGen = "\p#######.####;-#######.####;0.0"; NumFormatString formatRecGen; #endif void InitStdLib() { #ifdef USE_FORMATX2STR #ifdef USE_ITL int idx; #endif if (!partsTbl) { IUGetItlTable(iuSystemScript, iuNumberPartsTable, (Handle*)(&interRess), &partsOffset, &partsLength); HLock((Handle)interRess); partsTbl = (NumberPartsPtr)NewPtr(partsLength); LoadResource((Handle)interRess); BlockMove((Ptr)(*interRess) + partsOffset, partsTbl, partsLength); HUnlock((Handle)interRess); } #ifdef USE_ITL if (0 == decSeparat) { // decSeparat = (partsTbl->data[tokDecPoint]).a[1]; is not portable. Does not work with CW 6.0 hitl0Data = IUGetIntl(0); /* don't use GetResource */ decSeparat = (*(Intl0Hndl)hitl0Data)->decimalPt; } if ('.' != decSeparat) { for(idx=1; idx<=formatDefGen[0]; idx++) { if ('.' == formatDefGen[idx]) { formatDefGen[idx] = decSeparat; } } } #endif erreur = Str2Format(formatDefGen, partsTbl, &formatRecGen); if (erreur) { ParamText("\pFloat num format","\perror",NULL,NULL); StopAlert(128, NULL); } #endif } #if !defined(USE_FORMATX2STR) && defined(__SC__) && __option(global_optimizer) #define SC_OPTIMIZE #pragma SC options(!global_optimizer) #pragma message "SC optim SOff" #endif double atof(Ptr sValue) { long lgBuf; #ifdef USE_FORMATX2STR long double dblValue; // double dblValue; extended80 xValueBuf; Boolean decSepPresent; int idxTmp,idx=0; Str63 tmp; idxTmp = 1; decSepPresent = false; #ifndef USE_ITL while( sValue[idx] && (('0'<=sValue[idx] && '9'>=sValue[idx]) || '.'==sValue[idx] || '-'==sValue[idx]) ) { if ( '.'==sValue[idx] ) #else while( sValue[idx] && (('0'<=sValue[idx] && '9'>=sValue[idx]) || decSeparat==sValue[idx] || '-'==sValue[idx]) ) { if ( decSeparat==sValue[idx] ) #endif decSepPresent = true; tmp[idxTmp++] = sValue[idx++]; } tmp[0] = idxTmp-1; if (decSepPresent) { // If decimal separator is missing, returns 1 as error status erreur = FormatStr2X(tmp, &formatRecGen, partsTbl, &xValueBuf); if (erreur) { ParamText("\pAtof","\pFormatStr2X",tmp,"\perror"); StopAlert(128, NULL); return 0; } x80told ( &xValueBuf, &dblValue ); // dblValue = x80tod ( &xValueBuf ); } else { // Just convert the integer value StringToNum(tmp, &lgBuf); dblValue = (double)lgBuf; } // Check for exponent if ( 'e'==sValue[idx] || 'E'==sValue[idx] ) { ++idx; } else { return (double)dblValue; } idxTmp = 1; while( sValue[idx] && (('0'<=sValue[idx] && '9'>=sValue[idx]) || '-'==sValue[idx]) ) tmp[idxTmp++] = sValue[idx++]; tmp[0] = idxTmp-1; StringToNum(tmp, &lgBuf); return (double)dblValue * pow(10, lgBuf); #else int idx; double result, fpPow; Boolean chgSgn; idx=0; result = 0; if ('-' == sValue[idx]) { chgSgn = true; ++idx; } else { chgSgn = false; } #ifndef USE_ITL while ( 0!=sValue[idx] && '.'!=sValue[idx] ) { #else while ( 0!=sValue[idx] && decSeparat!=sValue[idx] ) { #endif result = result*10 + (sValue[idx]-48); ++idx; } #ifndef USE_ITL if ('.'==sValue[idx]) ++idx; #else if (decSeparat==sValue[idx]) ++idx; #endif fpPow = 1; while ( sValue[idx]>='0' && sValue[idx]<='9' ) { fpPow /= 10; result += (sValue[idx]-48) * fpPow; ++idx; } if (chgSgn) result = -result; // Check for exponent if ( 'e'==sValue[idx] || 'E'==sValue[idx] ) { ++idx; } else { return result; } if ( '-' == sValue[idx] ) { chgSgn = true; ++idx; } else { chgSgn = false; } lgBuf = 0; while( '0'<=sValue[idx] && '9'>=sValue[idx] ) { lgBuf += lgBuf*10 + (sValue[idx]-48); ++idx; } if (chgSgn) lgBuf = -lgBuf; return result * pow(10, lgBuf); #endif } //!! 'E' ou 'e' font partie de la chaine à convertir. double strtod(const char *str, char **endptr) { int idx=0; #ifdef USE_FORMATX2STR Str63 tmp; int idxTmp; extended80 xValue; long double ldValue; long lgBuf; Boolean decSepPresent; #else int exp; double buf,result; Boolean chgSgn; #endif #ifdef USE_FORMATX2STR idxTmp = 1; decSepPresent = false; #ifndef USE_ITL while( str[idx] && (('0'<=str[idx] && '9'>=str[idx]) || '.'==str[idx] || '-'==str[idx]) ) { if ('.'==str[idxTmp]) #else while( str[idx] && (('0'<=str[idx] && '9'>=str[idx]) || decSeparat==str[idx] || '-'==str[idx]) ) { if (decSeparat==str[idxTmp]) #endif decSepPresent = true; tmp[idxTmp++] = str[idx++]; } tmp[0] = idxTmp-1; if (decSepPresent) { // If decimal separator is missing, returns 1 as error status erreur = FormatStr2X(tmp, &formatRecGen, partsTbl, &xValue); if (erreur) { ParamText("\pStrtod","\pFormatStr2X",tmp,"\perror"); StopAlert(128, NULL); if (endptr) *endptr = (char*)(str+idx); return 0; } x80told ( &xValue, &ldValue); } else { // Just convert the integer value StringToNum(tmp, &lgBuf); ldValue = (double)lgBuf; } // Check for exponent if ('e'==str[idx] || 'E'==str[idx]) { ++idx; } else { if (endptr) *endptr = (char*)(str+idx); return (double)ldValue; } idxTmp = 1; while( ('0'<=str[idx] && '9'>=str[idx]) || '-'==str[idx] ) tmp[idxTmp++] = str[idx++]; tmp[0] = idxTmp-1; StringToNum(tmp, &lgBuf); if (endptr) *endptr = (char*)(str+idx); return (double)ldValue * pow(10, lgBuf); #else idx = 0; result=0; if ('-' == str[idx]) { chgSgn = true; ++idx; } else { chgSgn = false; } while( '0'<=str[idx] && '9'>=str[idx] ) { result = result*10 + str[idx]-48; idx++; } #ifndef USE_ITL if ('.'==str[idx]) ++idx; #else if (decSeparat==str[idx]) ++idx; #endif buf = 0.1; while( '0'<=str[idx] && '9'>=str[idx] ) { result += buf*(str[idx]-48); buf /= 10; ++idx; } if (chgSgn) { result = -result; } if ( 'e'==str[idx] || 'E'==str[idx] ) { ++idx; exp= 0; if ( '-'==str[idx]) { chgSgn = true; ++idx; } else { chgSgn = false; } while( '0'<=str[idx] && '9'>=str[idx] ) { exp = exp*10 + str[idx]-48; idx++; } if (chgSgn) { exp = -exp; } result *= pow(10, exp); } if (endptr) *endptr = (char*)(str+idx); return result; #endif } #ifdef SC_OPTIMIZE #undef SC_OPTIMIZE #pragma SC options(global_optimizer) #pragma message "SC optim SOn" #endif