#define _GNU_SOURCE //asprintf #include #include #include #include #include #include __attribute__((noreturn)) void usage(int argc,char **argv){ (void)argc; fprintf(stderr, "Usage: %s [-co] \n" "Converts a number to (British) English word form.\n" "Currently supports only integers.\n" " -c Capitalise the first output letter\n" " -o Write as ordinal (first) instead of cardinal (one)\n", argv[0]); exit(1); } char *thousands[6]={"thousand","million","billion","trillion","quadrillion","quintillion"}; char *twenty[20]={ "zero","one","two","three","four","five","six","seven","eight","nine","ten", "eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen" }; char *tens[10]={ "zero","ten","twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety" }; char *ordtwenty[20]={ "zeroth","first","second","third","fourth","fifth","sixth","seventh","eighth","ninth","tenth", "eleventh","twelfth","thirteenth","fourteenth","fifteenth","sixteenth","seventeenth","eighteenth","nineteenth" }; char *ordtens[10]={ "zeroth","tenth","twentieth","thirtieth","fortieth","fiftieth","sixtieth","seventieth","eightieth","ninetieth" }; void addtobuf(char *text,char **buf){ int len=strlen(text); strcpy(*buf,text); *buf=*buf+len; } char* printnumber(intmax_t num,char *buf){ if(num<0){ addtobuf("minus ",&buf); num=-num; } bool hadth=false; if(num>=1000){ hadth=true; intmax_t th[6],nth=0,rest; rest=num%1000; num/=1000; while(num){ th[nth++]=num%1000; num/=1000; } bool first=true; while(nth-->0){ if(th[nth]==0)continue; if(!first)addtobuf(" ",&buf); buf=printnumber(th[nth],buf); addtobuf(" ",&buf); addtobuf(thousands[nth],&buf); first=false; } num=rest; if(num==0)return buf; addtobuf(" ",&buf); } bool and=(num>=100||hadth)&&num%100!=0; if(num>=100){ buf=printnumber(num/100,buf); addtobuf(" ",&buf); addtobuf("hundred",&buf); num%=100; if(num)addtobuf(" ",&buf); else return buf; } if(and)addtobuf("and ",&buf); if(num%10==0)addtobuf(tens[num/10],&buf); else if(num<20)addtobuf(twenty[num],&buf); else { addtobuf(tens[num/10],&buf); addtobuf("-",&buf); addtobuf(twenty[num%10],&buf); } return buf; } char* printordinal(intmax_t num,char *buf){ if(num<0){ addtobuf("minus ",&buf); num=-num; } bool hadth=false; if(num>=1000){ hadth=true; buf=printnumber(num/1000*1000,buf); num%=1000; if(num==0){ addtobuf("th",&buf); return buf; } addtobuf(" ",&buf); } if(hadth&&num/100==0&&num%100!=0)addtobuf("and ",&buf); if(num<20){ addtobuf(ordtwenty[num],&buf); return buf; } if(num<100){ if(num%10==0)addtobuf(ordtens[num/10],&buf); else { addtobuf(tens[num/10],&buf); addtobuf("-",&buf); addtobuf(ordtwenty[num%10],&buf); } return buf; } buf=printnumber(num/100*100,buf); if(num%100==0){ addtobuf("th",&buf); return buf; } addtobuf(" and ",&buf); return printordinal(num%100,buf); } int main(int argc,char **argv){ char *numstr=NULL; bool ordinal=false,capfirst=false; for(int i=1;i