/* Time-stamp: <2007-09-22 19:46:06 poser> * * Copyright (C) 2006, 2007 William J. Poser (billposer@alum.mit.edu) * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * or go to the web page: http://www.gnu.org/licenses/gpl.txt. */ #include "config.h" #include #include #include #include #include #ifdef HAVE_GETOPT_LONG #define _GNU_SOURCE #include #endif #include "unicode.h" #include "uninum.h" #include "nsdefs.h" #include "utf8error.h" #include "exitcode.h" #include "input.h" #ifndef HAVE_GETOPT_LONG struct option { # if (defined __STDC__ && __STDC__) || defined __cplusplus const char *name; # else char *name; # endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; int getopt_long(int ac, char *const *av, const char * sopts, const struct option *lopts, int *lind){ return(getopt(ac,av,sopts)); } #endif struct option opts[]={ {"help",0,NULL,'h'}, {"version",0,NULL,'v'}, {"input-base",1,NULL,'b'}, {"output-base",1,NULL,'B'}, {"from",1,NULL,'f'}, {"group-size",1,NULL,'g'}, {"low-group-size",1,NULL,'G'}, {"identify",1,NULL,'I'}, {"input-file",1,NULL,'i'}, {"roman-use-macron",0,NULL,'m'}, {"output-file",1,NULL,'o'}, {"use-locale-group-info",0,NULL,'L'}, {"list-number-systems",0,NULL,'l'}, {"list-number-system-cover-terms",0,NULL,'c'}, {"group-separator",1,NULL,'s'}, {"to",1,NULL,'t'}, {0,0,0,0} }; #define MSGSIZE 512 #define INPUT_TEXT_SIZE_INIT 32 char *pgname ="numconv"; char compdate[]="Compiled " __DATE__ " " __TIME__ ; void ShowNumberSystems(int which) { char *ds; while (ds = ListNumberSystems(1,which)) printf("%s\n",ds); } void Usage(FILE *fp){ fprintf(fp,"Filter to convert integers from one number system to another.\n"); fprintf(fp,"%s [options]\n",pgname); fprintf(fp,"If the number system is 'all', the number system will be autodetected\nfor each input line and the output will consist of the original string,\nthe name of the number system, and the result of the conversion.\nIf the number system is 'any', the number system of the first input\nline will be autodetected and assumed for all subsequent lines.\n"); fprintf(fp,"Options:\n"); fprintf(fp,"\t-b\t\t\t\n"); fprintf(fp,"\t-B\t\t\t\n"); fprintf(fp,"\t-c\tList the available number system cover terms.\n"); fprintf(fp,"\t-f\t\t\t\n"); fprintf(fp,"\t-g\t\t\t\n"); fprintf(fp,"\t-G\t\t\t\n"); fprintf(fp,"\t-h\tPrint help information.\n"); fprintf(fp,"\t-i\t\t\t\n"); fprintf(fp,"\t-I\tIdentify the number system of the input.\n"); #ifdef HAVE_LOCALECONV fprintf(fp,"\t-L\tSet output grouping parameters according to current locale.\n"); #endif fprintf(fp,"\t-l\tList the available number systems.\n"); fprintf(fp,"\t-m\tUse bar for thousands in roman numerals.\n"); fprintf(fp,"\t-o\t\t\t\n"); fprintf(fp,"\t-s\t\t\t\n"); fprintf(fp,"\t-t\t\t\t\n"); fprintf(fp,"\t-v\tPrint version information.\n"); } void ShowVersion(FILE *fp){ fprintf(fp,"%s %s\n",pgname,VERSION); fprintf(fp," lib uninum %s\n",uninum_version()); fprintf(fp," lib gmp %s\n",gmp_version); fprintf(fp,"%s\n",compdate); fprintf(fp,"Copyright (C) 2006-2007 William J. Poser\n"); fprintf(stderr,"This program is free software; you can redistribute it and/or modify\n"); fprintf(stderr,"it under the terms of version 2 of the GNU General Public License\n"); fprintf(stderr,"as published by the Free Software Foundation.\n"); fprintf(stderr,"Report bugs to: billposer@alum.mit.edu\n"); } char *StripSeparators(char *s, char d) { char *t; char *o; char c; o = t = s; while ((c = *s++) != '\0') if (c != d) *t++ = c; *t = '\0'; return o; } char msg[MSGSIZE+1]; int main(int ac, char **av) { UTF32 *line = NULL; int nr; int oc; unsigned long num; unsigned long LineCnt = 0L; int Base; int gns; int ins; int ons; int ans; FILE *infp; FILE *outfp; int lgoindex; /* Unused but needed by getopt_long */ short IdentifyOnlyP = 0; #ifdef HAVE_LOCALECONV short UseLocaleGroupInfoP = 0; #endif char *numstr; union ns_rval val; UTF32 *ptr = NULL; char *InputNumberSystem = NULL; char *OutputNumberSystem = NULL; char *InputFileName = NULL; char *OutputFileName = NULL; int InputTextSize = INPUT_TEXT_SIZE_INIT; int LineLength = 0; char *maxptr; extern int optind; extern char *optarg; extern int optopt; extern int opterr; extern int getopt(int,char * const [],const char *); extern void putu8s(UTF32 *,FILE *); extern void fputu8(UTF32,FILE *); extern UTF32 *wcgetline(FILE *, int *,unsigned long); opterr = 0; while( (oc = getopt_long(ac,av,":B:b:cf:G:g:hi:IlLmo:s:t:v",opts,&lgoindex)) != EOF){ switch(oc){ case 'b': Uninum_Input_Base = atoi(optarg); break; case 'B': Uninum_Output_Base = atoi(optarg); break; case 'f': InputNumberSystem = optarg; break; case 'g': Uninum_Output_General_Group_Size = atoi(optarg); break; case 'G': Uninum_Output_First_Group_Size = atoi(optarg); break; case 'i': InputFileName = optarg; break; case 'm': Uninum_Generate_Roman_With_Bar_P = 1; break; case 'o': OutputFileName = optarg; break; case 's': Uninum_Output_Group_Separator = optarg[0]; break; case 't': OutputNumberSystem = optarg; break; case 'h': Usage(stdout); exit(2); case 'I': IdentifyOnlyP = 1; break; #ifdef HAVE_LOCALECONV case 'L': UseLocaleGroupInfoP = 1; break; #endif case 'c': ShowNumberSystems(1); exit(2); case 'l': ShowNumberSystems(0); exit(2); case 'v': ShowVersion(stdout); exit(2); case ':': fprintf(stderr,"%s: option flag %c requires an argument.\n",pgname,optopt); exit(1); case '?': fprintf(stderr,"%s: invalid option flag %c\n",pgname,optopt); exit(1); } } if(InputNumberSystem == NULL) InputNumberSystem = "all"; if(OutputNumberSystem == NULL) OutputNumberSystem = "Western_Lower"; if(InputFileName) { infp = fopen(InputFileName,"r"); if(infp == NULL) { snprintf(msg,MSGSIZE,"Unable to open input file %s",InputFileName); perror(msg); exit(OPENERROR); } } else infp = stdin; if(OutputFileName) { outfp = fopen(OutputFileName,"w"); if(outfp == NULL) { snprintf(msg,MSGSIZE,"Unable to open output file %s",OutputFileName); perror(msg); exit(OPENERROR); } } else outfp = stdout; if(!IdentifyOnlyP) { ins = StringToNumberSystem(InputNumberSystem); if(ins == NS_UNKNOWN) { fprintf(stderr,"Number system %s not recognized.\n",InputNumberSystem); exit(1); } ons = StringToNumberSystem(OutputNumberSystem); if(ons == NS_UNKNOWN) { fprintf(stderr,"Number system %s not recognized.\n",OutputNumberSystem); exit(1); } if(uninum_ns_type != NS_TYPE_SAFE) { fprintf(stderr,"Number system %s is not suitable for string generation.\n", OutputNumberSystem); exit(1); } } #ifdef HAVE_LOCALECONV if(UseLocaleGroupInfoP) GetLocaleGroupInfo(); #endif while (1) { if(line) free(line); if(ptr) free(ptr); line=wcgetline(infp, &LineLength,LineCnt); if(LineLength == -1) { /* EOF */ break; } if(LineLength == 0) { LineCnt++; putchar('\n'); continue; } LineCnt++; if(IdentifyOnlyP) { gns = GuessNumberSystem(line); if ( (gns == NS_UNKNOWN) || (gns == NS_ALLZERO)) { printf("Cannot identify number system.\n"); continue; } else { fprintf(outfp,"%s\n",NumberSystemToString(gns)); continue; } } if (ins == NS_ALL) { gns = GuessNumberSystem(line); if(gns == NS_UNKNOWN) { printf("Cannot identify input number system.\n"); continue; } ans = gns; } else ans = ins; if(ans != NS_ALLZERO) { StringToInt(&val,line,NS_TYPE_STRING,ans); if(uninum_err == NS_ERROR_BADCHARACTER) { fprintf(stderr,"Character "); fputu8(uninum_badchar,stderr); fprintf(stderr, "U+%04X illegal in number system %s detected at line %d.\n", uninum_badchar, NumberSystemToString(ans), LineCnt); continue; } if(uninum_err == NS_ERROR_NOTCONSISTENTWITHBASE) { fprintf(stderr,"Input contains a character inconsistent with the base.\n"); continue; } if(uninum_err == NS_ERROR_OKAY) { ptr = IntToString(&val,ons,NS_TYPE_STRING); } } else { val.u = 0L; ptr = IntToString(&val,ons,NS_TYPE_ULONG); } switch(uninum_err) { case NS_ERROR_RANGE: fprintf(stderr,"%s falls outside the range of the %s number system\n", val.s,NumberSystemToString(ons)); maxptr = UninumStringMaximumValue(ons); if(maxptr) { fprintf(stderr,"Values must be non-negative. The maximum expressible is: %s\n",maxptr); free(maxptr); } break; case NS_ERROR_NOZERO: fprintf(stderr,"The %s number system cannot represent zero in base %d.\n", NumberSystemToString(ons),Uninum_Output_Base); break; case NS_ERROR_OUTOFMEMORY: fprintf(stderr,"Failed to allocate memory.\n"); exit(OUTOFMEMORY); break; /* NOTREACHED */ case NS_ERROR_OKAY: if(ptr != NULL) {putu8s(ptr,outfp);putc('\n',outfp);} else fprintf(stderr,"Pointer is null.\n"); break; default: fprintf(stderr,"Unknown error.\n"); break; } } /* End of while loop over input lines */ exit(0); }