summaryrefslogtreecommitdiff
path: root/Build/source/texk/upmendex/fwrite.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/upmendex/fwrite.c')
-rw-r--r--Build/source/texk/upmendex/fwrite.c899
1 files changed, 899 insertions, 0 deletions
diff --git a/Build/source/texk/upmendex/fwrite.c b/Build/source/texk/upmendex/fwrite.c
new file mode 100644
index 00000000000..75ae1591d59
--- /dev/null
+++ b/Build/source/texk/upmendex/fwrite.c
@@ -0,0 +1,899 @@
+#include "mendex.h"
+
+#include <stdarg.h>
+
+#include <kpathsea/tex-file.h>
+#include <unicode/unorm2.h>
+
+#include "exkana.h"
+#include "exhanzi.h"
+#include "exvar.h"
+
+int line_length=0;
+
+static void printpage(struct index *ind, FILE *fp, int num, char *lbuff);
+static int range_check(struct index ind, int count, char *lbuff);
+static void linecheck(char *lbuff, char *tmpbuff);
+static void crcheck(char *lbuff, FILE *fp);
+static void index_normalize(UChar *istr, UChar *ini, int *chset);
+static int initial_cmp_char(UChar *ini, UChar ch);
+static int init_hanzi_header(void);
+static const UNormalizer2* unormalizer_NFD;
+static int turkish_i;
+
+#define M_NONE 0
+#define M_TO_UPPER 1
+#define M_TO_TITLE 2
+#define M_TO_LOWER -1
+
+#define CHOSEONG_KIYEOK 0x1100
+
+/* All buffers have size BUFFERLEN. */
+#define BUFFERLEN 4096
+
+#ifdef HAVE___VA_ARGS__
+/* Use C99 variadic macros if they are supported. */
+/* We would like to use sizeof(buf) instead of BUFFERLEN but that fails
+ for, e.g., gcc-4.8.3 on Cygwin and gcc-4.5.3 on NetBSD. */
+#define SPRINTF(buf, ...) \
+ snprintf(buf, BUFFERLEN, __VA_ARGS__)
+#define SAPPENDF(buf, ...) \
+ snprintf(buf + strlen(buf), BUFFERLEN - strlen(buf), __VA_ARGS__)
+#else
+/* Alternatively use static inline functions. */
+static inline int SPRINTF(char *buf, const char *format, ...)
+{
+ va_list argptr;
+ int n;
+
+ va_start(argptr, format);
+ n = vsnprintf(buf, BUFFERLEN, format, argptr);
+ va_end(argptr);
+
+ return n;
+}
+static inline int SAPPENDF(char *buf, const char *format, ...)
+{
+ va_list argptr;
+ int n;
+
+ va_start(argptr, format);
+ n = vsnprintf(buf + strlen(buf), BUFFERLEN - strlen(buf), format, argptr);
+ va_end(argptr);
+
+ return n;
+}
+#endif
+
+static void fprint_uchar(FILE *fp, const UChar *a, const int mode, const int len)
+{
+ int k;
+ char str[15], *ret;
+ UChar istr[5];
+ int olen, wclen;
+ UErrorCode perr;
+
+ if (len<0) {
+ for (k=0; a[k] || k<4; k++) istr[k]=a[k];
+ wclen=k;
+ } else {
+ wclen = is_surrogate_pair(a) ? 2 : 1;
+ istr[0]=a[0];
+ if (wclen==2) istr[1]=a[1];
+ }
+ istr[wclen]=L'\0';
+ if (mode==M_TO_UPPER) {
+ perr = U_ZERO_ERROR;
+ u_strToUpper(istr,5,istr,wclen,"",&perr);
+ } else if (mode==M_TO_LOWER) {
+ perr = U_ZERO_ERROR;
+ u_strToLower(istr,5,istr,wclen, istr[0]==0x130&&turkish_i?"tr":"", &perr);
+ } else if (mode==M_TO_TITLE) {
+ perr = U_ZERO_ERROR;
+ u_strToTitle(istr,5,istr,wclen,NULL,"",&perr);
+ }
+ perr = U_ZERO_ERROR;
+ ret = u_strToUTF8(str, 15, &olen, istr, wclen, &perr);
+ fprintf(fp,"%s",str);
+}
+
+#ifdef WIN32
+/* fprintf with convert kanji code */
+int fprintf2(FILE *fp, const char *format, ...)
+{
+ char print_buff[8000];
+ va_list argptr;
+ int n;
+
+ va_start(argptr, format);
+ n = vsnprintf(print_buff, sizeof print_buff, format, argptr);
+ va_end(argptr);
+
+ fputs(print_buff, fp);
+ return n;
+}
+#endif
+
+void warn_printf(FILE *fp, const char *format, ...)
+{
+ char print_buff[8000];
+ va_list argptr;
+
+ va_start(argptr, format);
+ vsnprintf(print_buff, sizeof print_buff, format, argptr);
+ va_end(argptr);
+
+ warn++;
+ fputs(print_buff, stderr);
+ if (fp!=stderr) fputs(print_buff, fp);
+}
+
+void verb_printf(FILE *fp, const char *format, ...)
+{
+ char print_buff[8000];
+ va_list argptr;
+
+ va_start(argptr, format);
+ vsnprintf(print_buff, sizeof print_buff, format, argptr);
+ va_end(argptr);
+
+ if (verb!=0) fputs(print_buff, stderr);
+ if (fp!=stderr) fputs(print_buff, fp);
+}
+
+
+/* write ind file */
+void indwrite(char *filename, struct index *ind, int pagenum)
+{
+ int i,j,hpoint=0,tpoint=0;
+ char lbuff[BUFFERLEN],obuff[BUFFERLEN];
+ UChar datama[256],initial[INITIALLENGTH],initial_prev[INITIALLENGTH];
+ int chset,chset_prev;
+ FILE *fp;
+ UErrorCode perr;
+
+ if (filename && kpse_out_name_ok(filename)) fp=fopen(filename,"wb");
+ else {
+ fp=stdout;
+#ifdef WIN32
+ setmode(fileno(fp), _O_BINARY);
+#endif
+ }
+
+ convert(atama,datama);
+ fputs(preamble,fp);
+
+ if (fpage>0) {
+ fprintf(fp,"%s%d%s",setpage_prefix,pagenum,setpage_suffix);
+ }
+ perr=U_ZERO_ERROR;
+ unormalizer_NFD=unorm2_getInstance(NULL, "nfc", UNORM2_DECOMPOSE, &perr);
+
+ for (i=line_length=0;i<lines;i++) {
+ index_normalize(ind[i].dic[0], initial, &chset);
+ if (i==0) {
+ if ((CH_LATIN<=chset&&chset<=CH_GREEK) || chset==CH_HANZI) {
+ if (lethead_flag!=0) {
+ fputs(lethead_prefix,fp);
+ fprint_uchar(fp,initial,lethead_flag,-1);
+ fputs(lethead_suffix,fp);
+ }
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[0]);
+ SPRINTF(lbuff,"%s%s",item_0,obuff);
+ }
+ else if (chset==CH_KANA) {
+ if (lethead_flag!=0) {
+ fputs(lethead_prefix,fp);
+ for (j=hpoint;j<(u_strlen(datama));j++) {
+ if (initial_cmp_char(initial,datama[j])) {
+ fprint_uchar(fp,&atama[j-1],M_NONE,1);
+ hpoint=j;
+ break;
+ }
+ }
+ if (j==(u_strlen(datama))) {
+ fprint_uchar(fp,&atama[j-1],M_NONE,1);
+ }
+ fputs(lethead_suffix,fp);
+ }
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[0]);
+ SPRINTF(lbuff,"%s%s",item_0,obuff);
+ for (hpoint=0;hpoint<(u_strlen(datama));hpoint++) {
+ if (initial_cmp_char(initial,datama[hpoint])) {
+ break;
+ }
+ }
+ }
+ else if (chset==CH_HANGUL) {
+ if (lethead_flag!=0) {
+ fputs(lethead_prefix,fp);
+ for (j=tpoint;j<(u_strlen(tumunja));j++) {
+ if (initial_cmp_char(initial,tumunja[j])) {
+ fprint_uchar(fp,&tumunja[j-1],M_NONE,1);
+ tpoint=j;
+ break;
+ }
+ }
+ if (j==(u_strlen(tumunja))) {
+ fprint_uchar(fp,&tumunja[j-1],M_NONE,1);
+ }
+ fputs(lethead_suffix,fp);
+ }
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[0]);
+ SPRINTF(lbuff,"%s%s",item_0,obuff);
+ for (tpoint=0;tpoint<(u_strlen(tumunja));tpoint++) {
+ if (initial_cmp_char(initial,tumunja[tpoint])) {
+ break;
+ }
+ }
+ }
+ else {
+ if (lethead_flag!=0) {
+ if (symbol_flag && strlen(symbol)) {
+ fprintf(fp,"%s%s%s",lethead_prefix,symbol,lethead_suffix);
+ }
+ else if (lethead_flag>0) {
+ fprintf(fp,"%s%s%s",lethead_prefix,symhead_positive,lethead_suffix);
+ }
+ else if (lethead_flag<0) {
+ fprintf(fp,"%s%s%s",lethead_prefix,symhead_negative,lethead_suffix);
+ }
+ }
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[0]);
+ SPRINTF(lbuff,"%s%s",item_0,obuff);
+ }
+ switch (ind[i].words) {
+ case 1:
+ SAPPENDF(lbuff,"%s",delim_0);
+ break;
+
+ case 2:
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[1]);
+ SAPPENDF(lbuff,"%s%s",item_x1,obuff);
+ SAPPENDF(lbuff,"%s",delim_1);
+ break;
+
+ case 3:
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[1]);
+ SAPPENDF(lbuff,"%s%s",item_x1,obuff);
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[2]);
+ SAPPENDF(lbuff,"%s%s",item_x2,obuff);
+ SAPPENDF(lbuff,"%s",delim_2);
+ break;
+
+ default:
+ break;
+ }
+ printpage(ind,fp,i,lbuff);
+ }
+ else {
+ index_normalize(ind[i-1].dic[0], initial_prev, &chset_prev);
+ if ((CH_LATIN<=chset&&chset<=CH_GREEK) || chset==CH_HANZI) {
+ if (chset!=chset_prev || ss_comp(initial,initial_prev)) {
+ fputs(group_skip,fp);
+ if (lethead_flag!=0) {
+ fputs(lethead_prefix,fp);
+ fprint_uchar(fp,initial,lethead_flag,-1);
+ fputs(lethead_suffix,fp);
+ }
+ }
+ }
+ else if (chset==CH_KANA) {
+ for (j=hpoint;j<(u_strlen(datama));j++) {
+ if (initial_cmp_char(initial,datama[j])) {
+ break;
+ }
+ }
+ if ((j!=hpoint)||(j==0)) {
+ hpoint=j;
+ fputs(group_skip,fp);
+ if (lethead_flag!=0) {
+ fputs(lethead_prefix,fp);
+ fprint_uchar(fp,&atama[j-1],M_NONE,1);
+ fputs(lethead_suffix,fp);
+ }
+ }
+ }
+ else if (chset==CH_HANGUL) {
+ for (j=tpoint;j<(u_strlen(tumunja));j++) {
+ if (initial_cmp_char(initial,tumunja[j])) {
+ break;
+ }
+ }
+ if ((j!=tpoint)||(j==0)) {
+ tpoint=j;
+ fputs(group_skip,fp);
+ if (lethead_flag!=0) {
+ fputs(lethead_prefix,fp);
+ fprint_uchar(fp,&tumunja[j-1],M_NONE,1);
+ fputs(lethead_suffix,fp);
+ }
+ }
+ }
+ else {
+ if (CH_LATIN<=chset_prev&&chset_prev<=CH_HANZI){
+ fputs(group_skip,fp);
+ if (lethead_flag!=0 && symbol_flag) {
+ if (strlen(symbol)) {
+ fprintf(fp,"%s%s%s",lethead_prefix,symbol,lethead_suffix);
+ }
+ else if (lethead_flag>0) {
+ fprintf(fp,"%s%s%s",lethead_prefix,symhead_positive,lethead_suffix);
+ }
+ else if (lethead_flag<0) {
+ fprintf(fp,"%s%s%s",lethead_prefix,symhead_negative,lethead_suffix);
+ }
+ }
+ }
+ }
+
+ switch (ind[i].words) {
+ case 1:
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[0]);
+ SAPPENDF(lbuff,"%s%s%s",item_0,obuff,delim_0);
+ break;
+
+ case 2:
+ if (u_strcmp(ind[i-1].idx[0],ind[i].idx[0])!=0 || u_strcmp(ind[i-1].dic[0],ind[i].dic[0])!=0) {
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[0]);
+ SAPPENDF(lbuff,"%s%s%s",item_0,obuff,item_x1);
+ }
+ else {
+ if (ind[i-1].words==1) {
+ SAPPENDF(lbuff,"%s",item_01);
+ }
+ else {
+ SAPPENDF(lbuff,"%s",item_1);
+ }
+ }
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[1]);
+ SAPPENDF(lbuff,"%s",obuff);
+ SAPPENDF(lbuff,"%s",delim_1);
+ break;
+
+ case 3:
+ if (u_strcmp(ind[i-1].idx[0],ind[i].idx[0])!=0 || u_strcmp(ind[i-1].dic[0],ind[i].dic[0])!=0) {
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[0]);
+ SAPPENDF(lbuff,"%s%s",item_0,obuff);
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[1]);
+ SAPPENDF(lbuff,"%s%s%s",item_x1,obuff,item_x2);
+ }
+ else if (ind[i-1].words==1) {
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[1]);
+ SAPPENDF(lbuff,"%s%s%s",item_01,obuff,item_x2);
+ }
+ else if (u_strcmp(ind[i-1].idx[1],ind[i].idx[1])!=0 || u_strcmp(ind[i-1].dic[1],ind[i].dic[1])!=0) {
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[1]);
+ if (ind[i-1].words==2) SAPPENDF(lbuff,"%s%s%s",item_1,obuff,item_12);
+ else SAPPENDF(lbuff,"%s%s%s",item_1,obuff,item_x2);
+ }
+ else {
+ SAPPENDF(lbuff,"%s",item_2);
+ }
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[i].idx[2]);
+ SAPPENDF(lbuff,"%s%s",obuff,delim_2);
+ break;
+
+ default:
+ break;
+ }
+ printpage(ind,fp,i,lbuff);
+ }
+ }
+ fputs(postamble,fp);
+
+ if (filename) fclose(fp);
+}
+
+/* write page block */
+static void printpage(struct index *ind, FILE *fp, int num, char *lbuff)
+{
+ int i,j,k,cc;
+ char buff[BUFFERLEN],tmpbuff[BUFFERLEN],errbuff[BUFFERLEN],obuff[BUFFERLEN];
+
+ buff[0]=tmpbuff[0]='\0';
+
+ crcheck(lbuff,fp);
+ line_length=strlen(lbuff);
+
+ for(j=0;j<ind[num].num;j++) {
+ cc=range_check(ind[num],j,lbuff);
+ if (cc>j) {
+ if (pnumconv(ind[num].p[j].page,ind[num].p[j].attr[0])==pnumconv(ind[num].p[cc].page,ind[num].p[cc].attr[0])) {
+ j=cc-1;
+ continue;
+ }
+/* range process */
+ if (ind[num].p[j].enc[0]==range_open
+ || ind[num].p[j].enc[0]==range_close)
+ ind[num].p[j].enc++;
+ if (strlen(ind[num].p[j].enc)>0) {
+ SPRINTF(buff,"%s%s%s",encap_prefix,ind[num].p[j].enc,encap_infix);
+ }
+ if (strlen(suffix_3p)>0 && (pnumconv(ind[num].p[cc].page,ind[num].p[cc].attr[0])-pnumconv(ind[num].p[j].page,ind[num].p[j].attr[0]))==2) {
+ SAPPENDF(buff,"%s%s",ind[num].p[j].page,suffix_3p);
+ }
+ else if (strlen(suffix_mp)>0 && (pnumconv(ind[num].p[cc].page,ind[num].p[cc].attr[0])-pnumconv(ind[num].p[j].page,ind[num].p[j].attr[0]))>=2) {
+ SAPPENDF(buff,"%s%s",ind[num].p[j].page,suffix_mp);
+ }
+ else if (strlen(suffix_2p)>0 && (pnumconv(ind[num].p[cc].page,ind[num].p[cc].attr[0])-pnumconv(ind[num].p[j].page,ind[num].p[j].attr[0]))==1) {
+ SAPPENDF(buff,"%s%s",ind[num].p[j].page,suffix_2p);
+ }
+ else {
+ SAPPENDF(buff,"%s%s",ind[num].p[j].page,delim_r);
+ SAPPENDF(buff,"%s",ind[num].p[cc].page);
+ }
+ SAPPENDF(tmpbuff,"%s",buff);
+ buff[0]='\0';
+ if (strlen(ind[num].p[j].enc)>0) {
+ SAPPENDF(tmpbuff,"%s",encap_suffix);
+ }
+ linecheck(lbuff,tmpbuff);
+ j=cc;
+ if (j==ind[num].num) {
+ goto PRINT;
+ }
+ else {
+ SAPPENDF(tmpbuff,"%s",delim_n);
+ linecheck(lbuff,tmpbuff);
+ }
+ }
+ else if (strlen(ind[num].p[j].enc)>0) {
+/* normal encap */
+ if (ind[num].p[j].enc[0]==range_close) {
+ SPRINTF(errbuff,"Warning: Unmatched range closing operator \'%c\',",range_close);
+ for (i=0;i<ind[num].words;i++) {
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[num].idx[i]);
+ SAPPENDF(errbuff,"%s.",obuff);
+ }
+ warn_printf(efp, "%s\n", errbuff);
+ ind[num].p[j].enc++;
+ }
+ if (strlen(ind[num].p[j].enc)>0) {
+ SAPPENDF(tmpbuff,"%s%s%s",encap_prefix,ind[num].p[j].enc,encap_infix);
+ SAPPENDF(tmpbuff,"%s%s%s",ind[num].p[j].page,encap_suffix,delim_n);
+ linecheck(lbuff,tmpbuff);
+ }
+ else {
+ SAPPENDF(tmpbuff,"%s%s",ind[num].p[j].page,delim_n);
+ linecheck(lbuff,tmpbuff);
+ }
+ }
+ else {
+/* no encap */
+ SAPPENDF(tmpbuff,"%s%s",ind[num].p[j].page,delim_n);
+ linecheck(lbuff,tmpbuff);
+ }
+ }
+
+ if (ind[num].p[j].enc[0]==range_open) {
+ SPRINTF(errbuff,"Warning: Unmatched range opening operator \'%c\',",range_open);
+ for (k=0;k<ind[num].words;k++) {
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[num].idx[k]);
+ SAPPENDF(errbuff,"%s.",obuff);
+ }
+ warn_printf(efp, "%s\n", errbuff);
+ ind[num].p[j].enc++;
+ }
+ else if (ind[num].p[j].enc[0]==range_close) {
+ SPRINTF(errbuff,"Warning: Unmatched range closing operator \'%c\',",range_close);
+ for (k=0;k<ind[num].words;k++) {
+ widechar_to_multibyte(obuff,BUFFERLEN,ind[num].idx[k]);
+ SAPPENDF(errbuff,"%s.",obuff);
+ }
+ warn_printf(efp, "%s\n", errbuff);
+ ind[num].p[j].enc++;
+ }
+ if (strlen(ind[num].p[j].enc)>0) {
+ SAPPENDF(tmpbuff,"%s%s%s",encap_prefix,ind[num].p[j].enc,encap_infix);
+ SAPPENDF(tmpbuff,"%s%s",ind[num].p[j].page,encap_suffix);
+ }
+ else {
+ SAPPENDF(tmpbuff,"%s",ind[num].p[j].page);
+ }
+ linecheck(lbuff,tmpbuff);
+
+PRINT:
+ fputs(lbuff,fp);
+ fputs(delim_t,fp);
+ lbuff[0]='\0';
+}
+
+static int range_check(struct index ind, int count, char *lbuff)
+{
+ int i,j,k,cc1,cc2,start,force=0;
+ char tmpbuff[BUFFERLEN],errbuff[BUFFERLEN],obuff[BUFFERLEN];
+
+ for (i=count;i<ind.num+1;i++) {
+ if (ind.p[i].enc[0]==range_close) {
+ SPRINTF(errbuff,"Warning: Unmatched range closing operator \'%c\',",range_close);
+ widechar_to_multibyte(obuff,BUFFERLEN,ind.idx[0]);
+ SAPPENDF(errbuff,"%s.",obuff);
+ warn_printf(efp, "%s\n", errbuff);
+ ind.p[i].enc++;
+ }
+ if (ind.p[i].enc[0]==range_open) {
+ start=i;
+ ind.p[i].enc++;
+ for (j=i;j<ind.num+1;j++) {
+ if (strcmp(ind.p[start].enc,ind.p[j].enc)) {
+ if (ind.p[j].enc[0]==range_close) {
+ ind.p[j].enc++;
+ ind.p[j].enc[0]='\0';
+ force=1;
+ break;
+ }
+ else if (j!=i && ind.p[j].enc[0]==range_open) {
+ SPRINTF(errbuff,"Warning: Unmatched range opening operator \'%c\',",range_open);
+ for (k=0;k<ind.words;k++) {
+ widechar_to_multibyte(obuff,BUFFERLEN,ind.idx[k]);
+ SAPPENDF(errbuff,"%s.",obuff);
+ }
+ warn_printf(efp, "%s\n", errbuff);
+ ind.p[j].enc++;
+ }
+ if (strlen(ind.p[j].enc)>0) {
+ SPRINTF(tmpbuff,"%s%s%s",encap_prefix,ind.p[j].enc,encap_infix);
+ SAPPENDF(tmpbuff,"%s%s%s",ind.p[j].page,encap_suffix,delim_n);
+ linecheck(lbuff,tmpbuff);
+ }
+ }
+ }
+ if (j==ind.num+1) {
+ SPRINTF(errbuff,"Warning: Unmatched range opening operator \'%c\',",range_open);
+ for (k=0;k<ind.words;k++) {
+ widechar_to_multibyte(obuff,BUFFERLEN,ind.idx[k]);
+ SAPPENDF(errbuff,"%s.",obuff);
+ }
+ warn_printf(efp, "%s\n", errbuff);
+ }
+ i=j-1;
+ }
+ else if (prange && i<ind.num) {
+ if (chkcontinue(ind.p,i)
+ && (!strcmp(ind.p[i].enc,ind.p[i+1].enc)
+ || ind.p[i+1].enc[0]==range_open))
+ continue;
+ else {
+ i++;
+ break;
+ }
+ }
+ else {
+ i++;
+ break;
+ }
+ }
+ cc1=pnumconv(ind.p[i-1].page,ind.p[i-1].attr[0]);
+ cc2=pnumconv(ind.p[count].page,ind.p[count].attr[0]);
+ if (cc1>=cc2+2 || (cc1>=cc2+1 && strlen(suffix_2p)) || force) {
+ return i-1;
+ }
+ else return count;
+}
+
+/* check line length */
+static void linecheck(char *lbuff, char *tmpbuff)
+{
+ if (line_length+strlen(tmpbuff)>line_max) {
+ SAPPENDF(lbuff,"\n%s%s",indent_space,tmpbuff);
+ line_length=indent_length+strlen(tmpbuff);
+ tmpbuff[0]='\0';
+ }
+ else {
+ SAPPENDF(lbuff,"%s",tmpbuff);
+ line_length+=strlen(tmpbuff);
+ tmpbuff[0]='\0';
+ }
+}
+
+static void crcheck(char *lbuff, FILE *fp)
+{
+ int i;
+ char buff[BUFFERLEN];
+
+ for (i=strlen(lbuff);i>=0;i--) {
+ if (lbuff[i]=='\n') {
+ strncpy(buff,lbuff,i+1);
+ buff[i+1]='\0';
+ fputs(buff,fp);
+ strcpy(buff,&lbuff[i+1]);
+ strcpy(lbuff,buff);
+ break;
+ }
+ }
+}
+
+static void index_normalize(UChar *istr, UChar *ini, int *chset)
+{
+ int k, len, hi, lo, mi;
+ UChar ch,src[2],dest[8],strX[4],strY[4],strZ[4];
+ UErrorCode perr;
+ UCollationResult order;
+ static int hanzi_mode=0;
+
+ ch=istr[0];
+ *chset=charset(istr);
+ ini[1]=L'\0';
+
+ if (is_hiragana(ch)) {
+ ch+=KATATOP-HIRATOP; /* hiragana -> katakana */
+ }
+ if (is_katakana(ch)) {
+ ini[0]=kanatable[ch-KATATOP];
+ return;
+ }
+ if (is_extkana(ch)) {
+ ini[0]=extkanatable[ch-EXKANATOP];
+ return;
+ }
+ else if (ch==0x309F) { ini[0]=0x30E8; return; } /* HIRAGANA YORI */
+ else if (ch==0x30FF) { ini[0]=0x30B3; return; } /* KATAKANA KOTO */
+ else if (is_kor_hngl(&ch)) {
+ if ((ch>=0xAC00)&&(ch<=0xD7AF)) { /* Hangul Syllables */
+ ch=(ch-0xAC00)/(21*28)+CHOSEONG_KIYEOK; /* convert to Hangul Jamo, Initial consonants */
+ }
+ else switch (ch) {
+ case 0x3131: case 0xFFA1:
+ case 0x3200: case 0x320E: case 0x3260: case 0x326E:
+ ch=0x1100; break; /* ᄀ */
+ case 0x3132: case 0xFFA2:
+ ch=0x1101; break; /* ᄁ */
+ case 0x3134: case 0xFFA4:
+ case 0x3201: case 0x320F: case 0x3261: case 0x326F:
+ ch=0x1102; break; /* ᄂ */
+ case 0x3137: case 0xFFA7:
+ case 0x3202: case 0x3210: case 0x3262: case 0x3270:
+ ch=0x1103; break; /* ᄃ */
+ case 0x3138: case 0xFFA8:
+ ch=0x1104; break; /* ᄄ */
+ case 0x3139: case 0xFFA9:
+ case 0x3203: case 0x3211: case 0x3263: case 0x3271:
+ ch=0x1105; break; /* ᄅ */
+ case 0x3141: case 0xFFB1:
+ case 0x3204: case 0x3212: case 0x3264: case 0x3272:
+ ch=0x1106; break; /* ᄆ */
+ case 0x3142: case 0xFFB2:
+ case 0x3205: case 0x3213: case 0x3265: case 0x3273:
+ ch=0x1107; break; /* ᄇ */
+ case 0x3143: case 0xFFB3:
+ ch=0x1108; break; /* ᄈ */
+ case 0x3145: case 0xFFB5:
+ case 0x3206: case 0x3214: case 0x3266: case 0x3274:
+ ch=0x1109; break; /* ᄉ */
+ case 0x3146: case 0xFFB6:
+ ch=0x110A; break; /* ᄊ */
+ case 0x3147: case 0xFFB7:
+ case 0x3207: case 0x3215: case 0x3267: case 0x3275:
+ case 0x321D: case 0x321E: case 0x327E: /* ㈝ ㈞ ㉾ */
+ ch=0x110B; break; /* ᄋ */
+ case 0x3148: case 0xFFB8:
+ case 0x3208: case 0x3216: case 0x3268: case 0x3276:
+ case 0x321C: case 0x327D: /* ㈜ ㉽ */
+ ch=0x110C; break; /* ᄌ */
+ case 0x3149: case 0xFFB9:
+ ch=0x110D; break; /* ᄍ */
+ case 0x314A: case 0xFFBA:
+ case 0x3209: case 0x3217: case 0x3269: case 0x3277:
+ case 0x327C: /* ㉼ */
+ ch=0x110E; break; /* ᄎ */
+ case 0x314B: case 0xFFBB:
+ case 0x320A: case 0x3218: case 0x326A: case 0x3278:
+ ch=0x110F; break; /* ᄏ */
+ case 0x314C: case 0xFFBC:
+ case 0x320B: case 0x3219: case 0x326B: case 0x3279:
+ ch=0x1110; break; /* ᄐ */
+ case 0x314D: case 0xFFBD:
+ case 0x320C: case 0x321A: case 0x326C: case 0x327A:
+ ch=0x1111; break; /* ᄑ */
+ case 0x314E: case 0xFFBE:
+ case 0x320D: case 0x321B: case 0x326D: case 0x327B:
+ ch=0x1112; break; /* ᄒ */
+ }
+ ini[0]=ch;
+ return;
+ }
+ else if (len=is_hanzi(istr)) {
+ if (hanzi_mode==0) hanzi_mode=init_hanzi_header();
+ if (hanzi_mode==HANZI_UNKNOWN) {
+ u_strcpy(ini, hz_index[0].idx);
+ return;
+ }
+ strX[0] =istr[0];
+ if (len==2) strX[1] =istr[1];
+ strX[len]=L'\0';
+ lo=0; hi=hz_index_len;
+ while (lo<hi) {
+ mi = (lo+hi)/2;
+ u_strcpy(strZ,hz_index[mi].threshold);
+ order = ucol_strcoll(icu_collator, strZ, -1, strX, -1);
+ if (order!=UCOL_GREATER) lo=mi+1;
+ else hi=mi;
+ }
+ u_strcpy(ini,hz_index[lo-1].idx);
+ return;
+ }
+ if (ch==0x049||ch==0x069||ch==0x130||ch==0x131||ch==0x0CE||ch==0x0EE) {
+ /* check dotted/dotless İ,I,i,ı and Î,î for Turkish */
+ strX[0] = 0x131; strX[1] = 0x5A; strX[2] = 0x00; /* ıZ */
+ strZ[0] = 0x069; strZ[1] = 0x00; /* i */
+ order = ucol_strcoll(icu_collator, strZ, -1, strX, -1);
+ if (order==UCOL_GREATER) {
+ ini[0] = (ch==0x049||ch==0x131) ? 0x131 : 0x130; /* ı or İ */
+ turkish_i=1;
+ return;
+ }
+ }
+ if (ch==0x0C6||ch==0x0E6||ch==0x152||ch==0x153||ch==0x132||ch==0x133
+ ||ch==0x0DF||ch==0x1E9E||ch==0x13F||ch==0x140||ch==0x490||ch==0x491) {
+ strX[0] = u_toupper(ch); strX[1] = 0x00; /* ex. "Æ" "Œ" */
+ switch (ch) {
+ case 0x0C6: case 0x0E6: /* Æ æ */
+ strZ[0] = 0x41; break; /* A */
+ case 0x152: case 0x153: /* Œ œ */
+ strZ[0] = 0x4F; break; /* O */
+ case 0x0DF: case 0x1E9E: /* ß ẞ */
+ strZ[0] = 0x53; break; /* S */
+ case 0x132: case 0x133: /* IJ ij */
+ strZ[0] = 0x59; /* Y */
+ strZ[1] = 0x00;
+ if (ucol_equal(icu_collator, strZ, -1, strX, -1)) { ini[0]=0x59; return; }
+ strZ[0] = 0x49; break; /* I */
+ case 0x13F: case 0x140: /* Ŀ ŀ */
+ strZ[0] = 0x4C; break; /* L */
+ case 0x490: case 0x491: /* Ґ ґ */
+ strZ[0] = 0x413; break; /* Г */
+ }
+ strZ[1] = (ch==0x490||ch==0x491) ? 0x42F : 0x5A;
+ strZ[2] = 0x00; /* ex. "AZ" "OZ" "ГЯ" */
+ order = ucol_strcoll(icu_collator, strZ, -1, strX, -1);
+ if (order==UCOL_GREATER) { ini[0]=strZ[0]; return; } /* not ligature */
+ }
+ else if ((is_latin(&ch)&&ch>0x7F)||
+ (is_cyrillic(&ch)&&(ch<0x410||ch==0x419||ch==0x439||ch>0x44F))||
+ (is_greek(&ch)&&(ch<0x391||(ch>0x3A9&&ch<0x3B1)||ch>0x3C9))) { /* check diacritic */
+ src[0]=ch; src[1]=0x00;
+ perr=U_ZERO_ERROR;
+ unorm2_normalize(unormalizer_NFD, src, 1, dest, 8, &perr);
+ if (U_SUCCESS(perr)) {
+ if (is_latin(&ch)) { strZ[1] = 0x05A; } /* Z */
+ else if (is_cyrillic(&ch)) { strZ[1] = 0x42F; } /* Я */
+ else { strZ[1] = 0x3A9; } /* Ω */
+ strZ[0] = u_toupper(dest[0]); strZ[2] = 0x00; /* ex. "AZ" */
+ strX[0] = u_toupper(ch); strX[1] = 0x00; /* ex. "Å" */
+ order = ucol_strcoll(icu_collator, strZ, -1, strX, -1);
+ if (order==UCOL_LESS) { ini[0]=strX[0]; return; } /* with diacritic */
+ ch=dest[0]; /* without diacritic */
+ }
+ }
+ if (is_latin(istr)&&u_strlen(istr)>1) {
+ for(k=0; k<(u_strlen(istr)>2 ? 3 : 2); k++) {
+ strX[k]=u_toupper(istr[k]);
+ }
+ strX[k]=L'\0';
+ /* DZ, SZ or DZS for Hungarian, ad-hoc treatment */
+ if ((strX[0]==0x44 || strX[0]==0x53) && strX[1]==0x5A) { /* DZ SZ */
+ strY[0]=0x44; strY[1]=0x5A; strY[2]=0x53; strY[3]=L'\0'; /* DZS */
+ strZ[0]=0x44; strZ[1]=0x5A; strZ[2]=0x5A; strZ[3]=L'\0'; /* DZZ */
+ order = ucol_strcoll(icu_collator, strZ, -1, strY, -1);
+ if (order==UCOL_LESS) {
+ ini[0]=strX[0]; ini[1]=strX[1];
+ if (strX[0]==0x44 && strX[2]==0x53) { /* DZS */
+ ini[2]=0x53; ini[3]=L'\0';
+ } else { /* DZ SZ */
+ ini[2]=L'\0';
+ }
+ return;
+ }
+ }
+ /* DZ, DŽ for Slovak or Serbo-Croatian, ad-hoc treatment */
+ if (strX[0]==0x44 && (strX[1]==0x5A || strX[1]==0x17D)) { /* DZ DŽ */
+ strY[0]=0x44; strY[1]=0x17D; strY[2]=L'\0'; /* DŽ */
+ strZ[0]=0x44; strZ[1]=0x5A; strZ[2]=0x5A; strZ[3]=L'\0'; /* DZZ */
+ order = ucol_strcoll(icu_collator, strZ, -1, strY, -1);
+ if (order==UCOL_LESS) {
+ if (strX[1]==0x5A) {
+ strY[0]=0xD4; strY[1]=L'\0'; /* Ô */
+ strZ[0]=0x4F; strZ[1]=0x5A; strZ[2]=L'\0'; /* OZ */
+ order = ucol_strcoll(icu_collator, strZ, -1, strY, -1);
+ if (order==UCOL_LESS) { /* Slovak DZ */
+ ini[0]=strX[0]; ini[1]=strX[1];
+ ini[2]=L'\0';
+ return;
+ }
+ } else {
+ ini[0]=strX[0]; ini[1]=strX[1]; /* DŽ */
+ ini[2]=L'\0';
+ return;
+ }
+ }
+ }
+ /* other digraphs */
+ if(((strX[0]==0x43 || strX[0]==0x44 || strX[0]==0x53 || strX[0]==0x54 || strX[0]==0x58 || strX[0]==0x5A)
+ && strX[1]==0x48) || /* CH DH SH TH XH ZH */
+ (strX[0]==0x4C && strX[1]==0x4C) || /* LL */
+ ((strX[0]==0x47 || strX[0]==0x4C || strX[0]==0x4E) && strX[1]==0x4A) || /* GJ LJ NJ */
+ (strX[0]==0x52 && strX[1]==0x52) || /* RR */
+ ((strX[0]==0x43 || strX[0]==0x5A) && strX[1]==0x53) || /* CS ZS */
+ ((strX[0]==0x47 || strX[0]==0x4C || strX[0]==0x4E || strX[0]==0x54) && strX[1]==0x59)) /* GY LY NY TY */
+ {
+ strX[2]=L'\0';
+ strZ[0]=strX[0]; strZ[1]=0x5A; strZ[2]=L'\0';
+ order = ucol_strcoll(icu_collator, strZ, -1, strX, -1);
+ if (order==UCOL_LESS) {
+ ini[0]=strX[0]; ini[1]=strX[1]; ini[2]=L'\0';
+ return;
+ }
+ }
+ }
+ ini[0]=u_toupper(ch);
+ return;
+}
+
+static int initial_cmp_char(UChar *ini, UChar ch)
+{
+ UChar initial_tmp[INITIALLENGTH],istr[2];
+ int chset;
+ istr[0]=ch;
+ istr[1]=L'\0';
+
+ index_normalize(istr, initial_tmp, &chset);
+ return (ss_comp(ini, initial_tmp)<0);
+}
+
+static int init_hanzi_header(void)
+{
+ UChar strX[2],*pch0,*pch1;
+ int k, hzmode;
+ struct hanzi_index *hz_idx_init;
+
+ strX[0]=0x5B57; strX[1]=L'\0';
+ if (ucol_strcoll(icu_collator, strX, -1, HZ_RADICAL[0].threshold, -1)==UCOL_GREATER) {
+ hzmode=HANZI_UNIHAN;
+ hz_idx_init=HZ_RADICAL;
+ } else
+ if (ucol_strcoll(icu_collator, strX, -1, HZ_STROKE[0].threshold, -1)==UCOL_GREATER) {
+ hzmode=HANZI_STROKE;
+ hz_idx_init=HZ_STROKE;
+ } else
+ if (ucol_strcoll(icu_collator, strX, -1, HZ_PINYIN[0].threshold, -1)==UCOL_GREATER) {
+ hzmode=HANZI_PINYIN;
+ hz_idx_init=HZ_PINYIN;
+ } else
+ if (ucol_strcoll(icu_collator, strX, -1, HZ_ZHUYIN[0].threshold, -1)==UCOL_GREATER) {
+ hzmode=HANZI_ZHUYIN;
+ hz_idx_init=HZ_ZHUYIN;
+ }
+ else {
+ hzmode=HANZI_UNKNOWN;
+ hz_idx_init=HZ_UNKNOWN;
+ }
+ for (k=0;k<HZIDXSIZE;k++) {
+ hz_index[k]=hz_idx_init[k];
+ if (!hz_index[k].idx[0]) break;
+ }
+ hz_index_len=k;
+
+ pch0=hanzi_head;
+ for (k=0;k<hz_index_len;k++) {
+ if (u_strlen(pch0)==0) break;
+ if ((pch1=u_strchr(pch0,L';'))>0) {
+ if (pch1-pch0>=INITIALLENGTH) {
+ warn_printf(efp, "\nWarning, Too long hanzi header.\n");
+ break;
+ }
+ u_strncpy(hz_index[k].idx,pch0,pch1-pch0);
+ hz_index[k].idx[pch1-pch0]=L'\0';
+ pch0=pch1+1;
+ } else {
+ if (u_strlen(pch0)>=INITIALLENGTH) {
+ warn_printf(efp, "\nWarning, Too long hanzi header.\n");
+ break;
+ }
+ u_strcpy(hz_index[k].idx,pch0);
+ break;
+ }
+ }
+
+ return hzmode;
+}