#include #include #include #include //typedef unsigned int size_t #include #include #define YES 1 #define NO 0 #define TEST_SHA256 NO #define DISABLE_BREAKPOINTS NO #define DEBUG_TRACE_LEVEL1 YES #define DEBUG_TRACE_LEVEL2 YES #define DEBUG_TRACE_LEVEL3 NO //////////////////////////////////////////////////////// // Number base conversion and other generic utilities // which will eventually be a part of a GDB type // environment for the P2 and related architectures. // // Copyright 1995-2019 glgorman@yahoo.com GNU/MIT // (lesser GPL library license) // // Usage: compiles and runs under FlexGUI // upload to the P2 and try it. // // Try entering 64551656546516165764651615616165146411 // or whatever and see what happens when you convert // from base 10 to base 16, or base 58 or base 137 // or whatever. // Then try entering 3.1415926535 the next time you are // prompted to input an INTEGER // // When you get to the debugger try some commands like // 'a'=ASSEMBLE 'b'=BREAKPOINTS(CLEAR/DISABLE/ENABLE/SET) // 'd'=DOWN, 'l'=LIST(disassembly), 'm'=monitor, 'p'=PROCESS // 'r'=RUN/RESUME,'s'=STACK TRACE, 'u'=UP 'w'=WATCH VARIABLE // 'z'=ZAP #define LINK_DBG(zzz) LINK_DBG#zzz #define TRAPID LINK_DBG(__LINE__) #define TRON _debug001 #define TROFF #if 0 %define TYPEGLOB(A) "_#"#A"#_" #define DECOMB(A) A #define SPECIAL_REORDER(A,B,C) A C B #define class SPECIAL_REORDER(A TYPEGLOB(B) TYPEGLOB(C)) #typedef struct A DECOMB(C) DECOMB(B)) #endif #define class typedef struct #define public #define private #define protected #define DEFAULT_STACK_DUMP 16 #define _str(ORD,VAL) static const char *ORD = VAL #define _dbg(X)_str(TRON,"X");X #define _TRACE_DEBUG_(_000_, VAL) int _000_ = VAL; void _BREAK_DEBUG_(char *, int, int *trap); #define _TRY_(xyzzy) _dbg(xyzzy) #define _THROW_(xyzzy) xyzzy #define _CATCH_(xyzzy) xyzzy /////////////////////////////////////////////////////// _str(pszBase58,"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"); _str(prompt001,"\n>"); _str(string012prompt002,"\n:"); _str(string001,"\nType in a long integer:"); _str(string002,"\nEnter base to convert from:"); _str(string003,"\nEnter base to convert to:"); _str(string004,"\nConverting string with size %d ... "); _str(string005,"\nConverting from base %d to base %d ... "); _str(string006,"\nIteration %d: bin value is %d, summation is %d."); _str(string007,"\nSquaring the binfactor array:"); _str(string008,"\nMultipling and redistibuting upper groups:"); _str(string009,"\nEntering conversion function:"); _str(string010,"\nCompressing to base %d:"); _str(string011,"\nPerforming pairwise translation:"); _str(string012,"\nWarning! group overrun, bin: %d value %d: Possible loss of data!"); _str(string013,"\nPropagating carries through bins:"); _str(string014,"\n%d divisions performed in convert function."); _str(string015,"\nExpanding from base %d to base %d:"); _str(string016,"\nConverting to base %d:"); _str(string017,"\nCompanding to base %d:"); _str(string018,"\nIt was a dark and stormy night ... "); _str(string019,"abc"); _str(string020,"\nIt was a dark and stormy night ... "); _str(string021,"\nConverting %d character string to array of unsigned int:"); _str(string022,"\nArray size is %d, Memory allocated at %08x:"); _str(string023,"\nNow convert the %d array to a 32 bit int."); _str(string024,"\n***DEBUG BREAKPOINT REACHED***"); _str(string025,"\nContext = %s, Line number = %d"); _str(string026,"\nPress ANY key to continue or ESC to DEBUG"); _str(string027,"\nStack Trace - return value is %d."); _str(string028,"\nAddress: %08x: Value: %12d | 0x%08x | ASCII %s"); _str(string029,"\nArray size is %d, Using GLOBAL STATIC buffer at %08x:"); _str(string030,"\nArray size is %d, Using LOCAL STATIC buffer at %08x:"); _str(string031,"\n%d bins filled:"); _str(string032," (BASE %d)"); // debugger help commands ... _str(string033,"\n'a'=ASSEMBLE, 'b'=BREAKPOINTS(CLEAR/DISABLE/ENABLE/SET)"); _str(string034,"\n'c'=CPU (Info, Status, Change CPU Type), 'd'=DOWN"); _str(string035,"\n'e'=EVAL(expression), 'l'=LIST(disassembly), 'm'=MONITOR"); _str(string036,"\n'p'=PROCESS, 'r'=RUN/RESUME,'s'=STACK TRACE, 'u'=UP"); _str(string037,"\n'w'=WATCH VARIABLE, 'x'=EXAMINE, 'z'=ZAP, '?'=THIS MENU"); // protocols and modulation systems _str(string038,"8VSB,8Q10B,ASCII,BASE58,BINHEX,DTMF,DVI,EBCDIC,FAT12/16/32,GCR68,GIF89"); _str(string039,"HDMI,I2C,JPEG,MIDI,MP3,MPEG2,NTSC,PAL,PPP,QAM,QPSK,SSH,SMPTE,SPDIF,"); _str(string040,"SPI,TCP/IP,UART(Serial/TTY).USB,VGA,VITERBI,WAV,XMODEM,YMODEM,ZMODEM"); // CPU types, whether supported or not ... _str(string041,"\nParallax P1 PASM"); _str(string042,"\nParallax P2 PASM"); _str(string043,"\nPDP-11"); _str(string044,"\nPERL ByteCode"); _str(string045,"\nJAVA ByteCode"); _str(string046,"\nPascal P-Code"); _str(string047,"\nMotorola 6800"); _str(string048,"\nMotorola 68040"); _str(string049,"\nMOS 6502C"); _str(string050,"\nApple SWEET 16"); _str(string051,"\nFalken WOPR"); _str(string052,"\nDaystrom M5"); _str(string053,"\nIBM 360/370"); _str(string054,"\nHAL 9000 Rev I"); _str(string055,"\nIntel 8080A"); _str(string056,"\nZilog Z80"); // additional debugging formatting _str(string057,"\n offset %d, k %d, j %d"); _str(string058,"\n%08x: (%08x) FLAGS=%01x CODE=%4d %-8s %s DEST=%04x, SOURCE=%04x"); typedef enum {false, true} bool; static bool debug = false; typedef struct { unsigned int *x; int alloc; int size; int sign; int base; } bignum; typedef struct { int flags; int inst; int czi; int dest_addr; int source_addr; } P2INST; #define OPCODE(FLAGS,OPER,CZI,DEST,SOURCE) ((FLAGS<<28)|(OPER<<21)|(CZI|<18)|(DEST<<9)|(SRC)) // do not remove these "opcodes", as they are here for testing and development of // a generic algorithm, as well as for future use in some genetic algorithms. // They will be removed from production builds as the situation warrants. static const char *opcodes[] = { "NOP","TAB","CAT","TAG","FEE","FIE","FOE","FUM","DOG","SBR","ILL","IG_","AND","THE","SLI","THY", "TOV","ESE","DID","GYR","EYE","IN_","THE","WAB","ALL","MIM","SY+","WER","THE","BOR","OGV","ESE", "IBM","HAL","BEN","DER","OBI","WAN","MIC","ROS","LOL","LET","SBC","PGE","WAL","VAX","HPX","WAN", "DEC","DNA","AAA","AAC","AAG","AAT","ACA","ACC","ACT","AGA","AGC","AGT","ATA","ATC","ATG","ATT", "FOO","BAR","BAZ","CMP","CAL","JMP","RPT","ROT","FL_","BYE","BIN","BOX","BEL","BRI","GCR","GRP", "MEM","STK","HEP","TTL","RTL","ABC","NBC","CBS","JMP","RET","CAA","CAC","CRC","CTC","CTU","007", "POS","NEG","ADD","SUB","MUL","MOD","DIV","MOV","BRK","DBG","CHK","SIN","COS","TAN","ENC","DEC", "WRI","TTE","EN+","BY+","GLG","GNU","ORA","NOT","GNU","TOO","THA","TIS","THE","QUE","STI","ONI", "FOR","TRA","ARG","PHE","TRY","CYS","RTS","CTS","DTR","NIL","CAT","TAG","DOG","TAG","BOW","WOW", "BOX","BOY","ALT","ARM","808","ZIG","ZAG","TUG","TOW","ZER","CPU","GPL","DOO","BEE","DOO","BEE", "DOO","WOP","DPP","WPA","FDR","JFK","KJV","MJB","NCC","SAT","ITW","ASA","ADA","RKA","AND","STO", "RMY","NIG","TWA","RMA","AND","THE","SWA","MPT","THI","NGS","TAG","GER","EDE","FRP","MTE","CRY", "PTA","ADD","ABS","EXP","LOG","SQR","LIN","REG","FFT","BAS","ECO","NVE","RSI","ONS","RSA","SHA", "BIT","SET","BTC","ORG","RET","HOR","VER","SUB","WAV","MP3","NRZ","USB","TTY","COM","DSK","FMT", "NOP","STR","POP","FAT","DIR","NEW","FRE","DEL","MAL","LOC","LPT","CAS","FLO","RTS","CTS","DTR", "HYD","HEL","LIT","BER","BOR","CAR","NIT","CAR","CDR","NEO","NAT","WWW","XXX","YYY","ZZZ","HCF", }; static const char *opcodes2[] = { "nop","ror","rol","sbr","shl","rcp","rcl","sar", "sal","add","addx","adds","addsx","sub","subx","subs", "cmp","cmpx","cmps","cmpr","cmpm","subr","cmpsub","fge", "fles","sumc","sumnc","sumz","sumz","bor","ogv","ese", "IBM","HAL","BEN","DER","OBI","WAN","MIC","ROS","LOL","LET","SBC","PGE","WAL","VAX","HPX","WAN", "DEC","DNA","AAA","AAC","AAG","AAT","ACA","ACC","ACT","AGA","AGC","AGT","ATA","ATC","ATG","ATT", "FOO","BAR","BAZ","CMP","CAL","JMP","RPT","ROT","FL_","BYE","BIN","BOX","BEL","BRI","GCR","GRP", "MEM","STK","HEP","TTL","RTL","ABC","NBC","CBS","JMP","RET","CAA","CAC","CRC","CTC","CTU","007", "POS","NEG","ADD","SUB","MUL","MOD","DIV","MOV","BRK","DBG","CHK","SIN","COS","TAN","ENC","DEC", "WRI","TTE","EN+","BY+","GLG","GNU","ORA","NOT","GNU","TOO","THA","TIS","THE","QUE","STI","ONI", "FOR","TRA","ARG","PHE","TRY","CYS","RTS","CTS","DTR","NIL","CAT","TAG","DOG","TAG","BOW","WOW", "BOX","BOY","ALT","ARM","808","ZIG","ZAG","TUG","TOW","ZER","CPU","GPL","DOO","BEE","DOO","BEE", "DOO","WOP","DPP","WPA","FDR","JFK","KJV","MJB","NCC","SAT","ITW","ASA","ADA","RKA","AND","STO", "RMY","NIG","TWA","RMA","AND","THE","SWA","MPT","THI","NGS","TAG","GER","EDE","FRP","MTE","CRY", "PTA","ADD","ABS","EXP","LOG","SQR","LIN","REG","FFT","BAS","ECO","NVE","RSI","ONS","RSA","SHA", "BIT","SET","BTC","ORG","RET","HOR","VER","SUB","WAV","MP3","NRZ","USB","TTY","COM","DSK","FMT", "NOP","STR","POP","FAT","DIR","NEW","FRE","DEL","MAL","LOC","LPT","CAS","FLO","RTS","CTS","DTR", "HYD","HEL","LIT","BER","BOR","CAR","NIT","CAR","CDR","NEO","NAT","WWW","XXX","YYY","ZZZ","HCF", }; void TRACE_DEBUG0(const char *str) { if (debug==true) printf(str); } void TRACE_DEBUG1 (const char *str, int val) { if (debug==true) printf(str,val); } void TRACE_DEBUG2 (const char *str, int val1, int val2) { if (debug==true) printf(str,val1,val2); } void TRACE_DEBUG3 (const char *str, int val1, int val2, int val3) { // if (debug==true) printf(str,val1,val2,val3); } const char *get_mnemonic (int idx) { // two operations - no operation // or "halt and catch fire!" // char *opcodes[] = {"NOP","HCF"}; // Fixme - load real opcodes ... const char *result; // if (idx>256) // idx = idx%256; switch (idx) { case 0: result = "_nop_"; break; case 8: result = "_add_"; break; case 16: result = "_cmp_"; break; case 48: result = "_mov_"; break; case 88: result = "_rdlong_"; break; case 107: result = "cogid/exit"; break; case 108: result = "_jmp_"; break; case 110: result = "_calla_"; break; default: result = opcodes2[idx]; break; } return result; } // probably broken - not even tested // todo - implement Propeller opcodes // add CNZ flags!!!! void decode(unsigned int opcode, P2INST *pcode) { int src = (opcode)&0x1ff; int dst = (opcode>>9)&0x1ff; int czi = (opcode>>18)&0x07; int inst = (opcode>>21)&0x7f; int flags = (opcode>>28)&0x0f; pcode->source_addr = src; pcode->dest_addr = dst; pcode->czi = czi; pcode->inst = inst; pcode->flags = flags; } void disassemble (int *begin, int *end) { static const char *czi[] = {"___","__I","_Z_","_ZI","C__","C_I","CZ_","CZI",""}; P2INST grx; const char *mnemonic; int *ptr; int val; for (ptr=begin;ptr<=end;ptr++) { val = (*ptr); decode(val,&grx); mnemonic = get_mnemonic(grx.inst); printf (string058, ptr, val, grx.flags, grx.inst,mnemonic, czi[grx.czi], grx.dest_addr, grx.source_addr ); } } // allows us to pass in a regular // int and get an int back // untested 12707/2019 inline int peek (unsigned int addr) { int *peek = (int*)addr; int value = (*peek); return value; } void poke32 (unsigned int addr, unsigned int value) { int *poke = (int*)addr; (*poke) = value; } int get_return_address() { volatile int retaddr; volatile int *retvec2 = (int*)(&retaddr-5); retaddr = (*retvec2); return retaddr; } void call_asm (int addr) { // Ask the driver of the big Yellow Taxi if he knows // how to get to Washington, Washington? D.C., or // the state? volatile int *retvec1 = ((int*)addr); volatile int *retvec2; volatile int retaddr; retvec2 = (int*)(&retvec1+5); *retvec2 = *retvec1; retaddr = (*retvec2); printf ("\nretvec1 %08x, rettvec2 %08x ADDRESS = %08x",retvec1,retvec2,retaddr); printf ("\nAttempting to call %08x",addr); // Calling the debugger from inside the debugger!!! // Dont you just love (hate recursion)!?! _TRACE_DEBUG_(TRAP,0xfadedcab) _BREAK_DEBUG_("void call_asm (int addr)",__LINE__,&TRAP); // ((void*)(addr))(); // doesent seem to work // printf ("\nFAILURE!"); // hijack the return address instead and // fake the call by using this function to // implement an indirect jump // GNU IS NOT UNIX! } void _BREAK_DEBUG_(const char *context, int line, int *trap) { char c; int _debug = 0; int *peek, hansel; int offset = 0; static int j, k, gretal; static char ascii[16]; printf(string024); int MONITOR_ADDR = 0xFC7AF; stack_trace: printf(string025,context,line); peek = trap-(DEFAULT_STACK_DUMP-2)+offset; for (j=0;j='0')&&(c<='9')) { val = c-'0'; } else if ((c>='a')&&(c<='z')) { val = c-'a'+10; } else if ((c>='A')&&(c<='Z')) { val = c-'A'+10; return; } else { c = -1; _TRACE_DEBUG_(TRAP,0xdeadbeef) _BREAK_DEBUG_("chartobase36(char c)",__LINE__,&TRAP); } // printf ("%c=%d,",c,val); return val; } int _ishex(char c) { int val; val = chartobase36(c); if (val==-1) return false; else return true; } void _report(bignum *data) { unsigned long *bin = data->x; unsigned long asbase = data->base; int binNum, binvalue, maxBin, spaces; static char hexchar[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','\0'}; maxBin = MAXBINS-1; while (bin[maxBin] == 0) maxBin = maxBin - 1; printf("\n"); if (maxBin > 50) { for (spaces = 50-(maxBin+50)%50; spaces > 1; spaces--) printf("."); } for (binNum = maxBin; binNum >= 0; binNum--) { binvalue = bin[binNum]; if (asbase==60) { printf("%02d",binvalue); if (binNum!=0) printf(":"); } else { if (binvalue<16) printf("%c",hexchar[binvalue]); else printf("(%d)",binvalue); } if (binNum%50 == 0) printf("\n"); } } void report(unsigned int *bin, int asbase) { bignum data; data.x = bin; data.alloc = MAXBINS; data.size = MAXBINS-1; data.base = asbase; _report (&data); } void report58(bignum *d) { int j, max_bin; printf("\n"); unsigned long *bin = d->x; max_bin = d->alloc-1; while ((bin[max_bin]==0)&&(max_bin>0)) max_bin--; for (j=max_bin;j>=0;j--) { printf("%c",pszBase58[bin[j]]); } printf("\n"); } void _report1(bignum *d) { unsigned int *bin; int j, max_bin; printf("\n"); max_bin= d->alloc-1; bin = d->x; while ((bin[max_bin]==0)&&(max_bin>0)) max_bin--; for (j=max_bin;j>=0;j--) { if (j==max_bin) printf("{"); else printf(","); printf("(%u)",bin[j]); if ((j%16==15)&(j!=0)) printf("\n"); } printf("}"); printf(" (BASE %d)",d->base); } void report1(unsigned int *bin,int binfactors,int base) { bignum d; d.x = bin; d.alloc = binfactors; d.size = binfactors; // d.base = -1; d.base = base; if (binfactors>MAXBINS) { _TRACE_DEBUG_(TRAP,0xdeadbeef) _BREAK_DEBUG_("void report1(unsigned int *bin,int binfactors)",__LINE__,&TRAP); } _report1(&d); } inline int _convert_string (char *input, int *output, int sz) { int j,k,binvalue, binsfilled, length; char nextchar; length = strlen(input); for (j=0;j0;k--) { output[k] = output[k-1]; } output[0] = binvalue; binsfilled++; } else { if (nextchar == '.') { _TRACE_DEBUG_(TRAP,0xdeadbeef) _BREAK_DEBUG_("inline int _convert_string (char *input, int *output, int sz)",__LINE__,&TRAP); } }} TRACE_DEBUG1(string031,binsfilled); // for (j=binsfilled-1;j>=0;j--) // printf("(%d)",output[j]); return binsfilled; } void convert_string (char *output, bignum *d) { int size = d->size; unsigned long *data = d->x; _convert_string (output,data,size); } int from_decimal(int *d, int sz) { int i; int result=0; TRACE_DEBUG1(string004,sz); for (i=sz-1;i>=0;i--) { result*=10; result+=d[i]; TRACE_DEBUG3(string006,sz-i,d[i],result); } return result; } int getint (const char *prompt) { char response[255]; int tbuf[64]; printf(prompt); printf(prompt001); gets(response); int sz = _convert_string (response,tbuf,64); result = from_decimal(tbuf,sz); return result; } int get_user_data(unsigned int *bin) { int binsfilled, binvalue,inputBase, j ,k ,length; char nextchar, response[255]; binsfilled = 0; while (binsfilled == 0) { fflush(stdin); printf(string001); printf(prompt001); binsfilled = 0; gets(response); length = strlen(response); nextchar = response[0]; if (nextchar == '&') { break; } binsfilled = _convert_string(response,bin,BinArraySize); } inputBase = getint (string002); return inputBase; } void expand(unsigned int *bin, unsigned int src, unsigned int dest) /* This is a short routine to perform changes of a number base when the target base is an exact root of the source base, i.e. a base16 number can be turned into a base4 number by simply mapping each bin value in the base16 system onto a sequence of base4 binvalues. */ { int j, k, numerals; unsigned maxbin = BinArraySize-1; unsigned int dividend; unsigned long binvalue; TRACE_DEBUG2(string015,src,dest); while ((bin[maxbin]==0)&&(maxbin!=0)) maxbin--; numerals = 0; dividend = src; while (dividend>1) { dividend = dividend/dest; numerals = numerals + 1; } for (j=maxbin;j>=0;j--) { binvalue = bin[j]; for (k=0;k 1) { product = product/sourcebase; compression++; } for (j=0;j<=maxbin/compression;j++) { product=0; for (k=compression-1;k>=0;k--) { product = product * sourcebase + bin[j* compression + k]; bin[j* compression + k] = 0; } bin[j] = product; } j++; while (bin[j] == 0) { maxbin = j; j--; } } int square(unsigned int *sequence,int length, int base) { int j,k; unsigned long carry, term; unsigned long temp[BinArraySize]; for (k=0; kx; ptr2 = src2->x; ptr3 = dest->x; for (i=0;i maxbin) maxbin -= 1; for (j=0;j maxbin) && (bin[index]!=0)) maxbin = index; } index = offset+k; bin[index] += carry; if ((index > maxbin) && (bin[index]!=0)) maxbin = offset+k; if (carry != 0) overflow = true; } // if (debug == true) // { // printf(string013); // report1(bin,maxbin+1,targetBase); // } } } int console_loop() { unsigned int *bins = get_static_buffer(); int destBase, currentBase, targetBase; currentBase = get_user_data(bins); destBase = getint (string003); printf (string005,currentBase,destBase); if (destBase<2) return-1; #if 0 _TRACE_DEBUG_(TRAP,0xdeadbeef) _BREAK_DEBUG_("int console_loop()",__LINE__,&TRAP); #endif if (currentBase<16) { targetBase = currentBase; while (targetBase < 16) targetBase = targetBase * currentBase; squeeze(bins,currentBase,targetBase); currentBase = targetBase; } /* New code to handle larger base choices with less frequent corruption of data */ if (currentBase>16) { int baseChoice, k; double logCurrentBase, logK, newtest, oldtest, power, temp; logCurrentBase = log(currentBase); oldtest = 1; for (k=2;k<=20;k++) { logK = log(k); temp = modf(logCurrentBase/logK,&power); newtest = logK*(power+1)-logCurrentBase; if (newtest < oldtest) { oldtest = newtest; baseChoice = k; } } targetBase = baseChoice; while (targetBase < currentBase) { targetBase = targetBase*baseChoice; } if (currentBase != targetBase) { TRACE_DEBUG2(string005,currentBase,targetBase); convert(bins,currentBase,targetBase); } if (targetBase != baseChoice) { expand(bins,targetBase,baseChoice); currentBase = baseChoice; } if (currentBase < destBase) { targetBase = currentBase; while (targetBase < destBase) targetBase *= currentBase; } targetBase /= currentBase; if (targetBase != currentBase) { squeeze(bins,currentBase,targetBase); currentBase = targetBase; } } targetBase = destBase; while (targetBase < currentBase) { targetBase = targetBase*destBase; } TRACE_DEBUG2(string005,currentBase,targetBase); convert(bins,currentBase,targetBase); if (targetBase != destBase) { expand(bins,targetBase,destBase); currentBase = targetBase; } report(bins,destBase); return 0; } void makeTestData() { int j,length; for (j=0;j0) group1 = argument; else group1 = -argument; triplet_label = 1; while (group1>0) { these_three_digits = group1%1000; group1 = group1/1000; if (these_three_digits!=0) { h_digit = these_three_digits/100; t_digit = (these_three_digits%100)/10; u_digit = (these_three_digits%10); if (h_digit!=0) { strncat_s(scratch,words[h_digit],strlen(words[h_digit])); strncat_s(scratch,magnifier[0],strlen(magnifier[0])); if ((t_digit!=0)||(u_digit!=0)) switch (triplet_label) { case 1: case 3: strncat_s(scratch," and ",5); break; case 2: case 4: strncat_s(scratch," ",1); break; } } if (t_digit!=0) { switch (t_digit) case 1: { strncat_s(scratch,words[these_three_digits%100], strlen(words[these_three_digits%100])); if (u_digit>2) strncat_s(scratch,"teen",4); break; case 2: strncat_s(scratch,words[20],strlen(words[20])); break; default: strncat_s(scratch,words[t_digit+10], strlen(words[t_digit+10])); strncat_s(scratch,words[21],strlen(words[21])); break;} if (((t_digit!=1)&&(u_digit!=0))) strncat_s(scratch,hyphen,1); } if (u_digit!=0) { switch (t_digit) case 1: { break; default: strncat_s(scratch,words[u_digit],strlen(words[u_digit])); break; } } } strncat_s(scratch, magnifier[triplet_label], strlen(magnifier[triplet_label])); if ((triplet_label>1)&&(these_three_digits>99)) strncat_s(scratch,", ",2); else strncat_s(scratch," ",1); triplet_label++; strncat_s(scratch, text, strlen(text)); strcpy_s(text,scratch); strcpy_s(scratch,""); } if (argument==0) { strncat_s(scratch,words[0],strlen(words[0])); strncat_s(scratch, text, strlen(text)); strcpy_s(text,scratch); } if (argument<0) { strncat_s(scratch,words[23],strlen(words[23])); strncat_s(scratch, text, strlen(text)); strcpy_s(text,scratch); } length = strlen(text); // result = new char [length+1]; strcpy_s (result,length+1,text); if (result [length-1]==' ') result [length-1]='\0'; return result; }