Subversion Repositories wimsdev

Rev

Rev 15777 | Rev 16987 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
  2.  *
  3.  *  This program is free software; you can redistribute it and/or modify
  4.  *  it under the terms of the GNU General Public License as published by
  5.  *  the Free Software Foundation; either version 2 of the License, or
  6.  *  (at your option) any later version.
  7.  *
  8.  *  This program is distributed in the hope that it will be useful,
  9.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  *  GNU General Public License for more details.
  12.  *
  13.  *  You should have received a copy of the GNU General Public License
  14.  *  along with this program; if not, write to the Free Software
  15.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  */
  17.  
  18. /*  This is an internal program,
  19.  * used to index modules for search engine.
  20.  */
  21.  
  22. #include "../Lib/libwims.h"
  23. #include "translator_.h"
  24. #include "suffix.h"
  25.  
  26. #define MAX_LANGS    MAX_LANGUAGES
  27. #define MAX_MODULES    65536
  28. char *moduledir=    "public_html/modules";
  29. char *sheetdir=     "public_html/bases/sheet";
  30. char *glossarydir=  "public_html/scripts/data/glossary";
  31. char *dicdir=       "public_html/bases";
  32. char *outdir=       "public_html/bases/site2";
  33. char *sheetoutdir=  "public_html/bases/sheet/index";
  34. char *glossaryoutdir=  "public_html/scripts/data/glossary/index";
  35. char *maindic=      "sys/words";
  36. char *groupdic=     "sys/wgrp/wgrp";
  37. char *suffixdic=    "sys/suffix";
  38. char *domaindic=    "sys/domaindic";
  39. char *ignoredic=    "sys/indignore";
  40. char *conffile=     "log/wims.conf";
  41. char *mlistbase=    "lists";
  42.  
  43. char lang[MAX_LANGS][4]={
  44.     "en","fr","cn","es","it","nl","si","ca","pt"
  45. };
  46. #define DEFAULT_LANGCNT    6
  47. char allang[MAX_LANGS][4]={
  48.     "en","fr","cn","es","it","nl","de","si","ca","pt"
  49. };
  50. #define allangcnt 8
  51. char ignore[MAX_LANGS][MAX_LINELEN+1];
  52. char mlistfile[MAX_LANGS][256];
  53. int langcnt;
  54. FILE *langf, *titf, *descf, *weightf, *robotf, *indf, *listf, *addrf, *serialf, *authorf, *versionf, *remf;
  55.  
  56. struct cat {
  57.     char *name;
  58.     char typ;
  59. } cat[]={
  60.     {"all_types", 'A'},
  61.     {"exercise",  'X'},
  62.     {"oef",       'O'},
  63.     {"tool",      'T'},
  64.     {"recreation",'R'},
  65.     {"reference", 'Y'},
  66.     {"document",  'D'},
  67.     {"popup",     'P'},
  68.     {"datamodule",'M'}
  69. };
  70. #define catno (sizeof(cat)/sizeof(cat[0]))
  71.  
  72. struct mod {
  73.     char *name;
  74.     unsigned char langs[MAX_LANGS];
  75.     int counts[MAX_LANGS];
  76.     int langcnt;
  77. } mod[MAX_MODULES];
  78.  
  79. // serial-> the name of the module indexed by serial, lang and its classe
  80. struct revmod {
  81.     char name[MAX_MODULELEN+1];
  82.     int lang;
  83.     int imod;
  84.     char keywords[MAX_FNAME];
  85. } revmod[MAX_MODULES];
  86. int modcnt;
  87.  
  88. char *mlist;
  89. char *sheetindex[]={
  90.   "title", "description",
  91.   "duration", "severity",
  92.   "level", "domain",
  93.   "keywords", "reserved1", "reserved2", "information"
  94. };
  95. /* correspond to the order of sheetindex */
  96. char *glindex[]={
  97.   "gl_title", "gl_description",
  98.   "", "",
  99.   "gl_level", "gl_domain",
  100.   "gl_keywords","","",""};
  101.  
  102. #define SHEETINDEX_NO (sizeof(sheetindex)/sizeof(sheetindex[0]))
  103. char gsindbuf[SHEETINDEX_NO+1][MAX_LINELEN+1];
  104.  
  105. /* do not modify the order, correspond to the order in the sheet file */
  106. enum{s_title, s_description,
  107.       s_duration, s_severity,
  108.       s_level, s_domain,
  109.       s_keywords, s_reserved1, s_reserved2,
  110.       s_information
  111. };
  112.  
  113. char *modindex[]={
  114.   "title", "description",
  115.   "author", "address", "copyright",
  116.   "version", "wims_version", "language",
  117.   "category", "level", "domain", "keywords",
  118.   "keywords_ca", "keywords_en", "keywords_fr", "keywords_it", "keywords_nl",
  119.   "title_ca", "title_en", "title_fr", "title_it", "title_nl",
  120.   "require"
  121. };
  122. #define MODINDEX_NO (sizeof(modindex)/sizeof(modindex[0]))
  123. char indbuf[MODINDEX_NO][MAX_LINELEN+1];
  124. enum{i_title, i_description,
  125.   i_author,i_address,i_copyright,
  126.   i_version,i_wims_version,i_language,
  127.   i_category,i_level,i_domain,i_keywords,
  128.   i_keywords_ca,i_keywords_en,i_keywords_fr,i_keywords_it,i_keywords_nl,
  129.   i_title_ca,i_title_en,i_title_fr,i_title_it,i_title_nl,
  130.   i_require
  131. };
  132.  
  133. char *module_special_file[]={
  134.   "intro","help","about"
  135. };
  136. #define MODSPEC_NO (sizeof(module_special_file)/sizeof(module_special_file[0]))
  137. char module_language[4];
  138.  
  139. char *mdicbuf, *gdicbuf, *ddicbuf, *gentry, *mentry, *dentry;
  140.  
  141. int gentrycount, mentrycount, dentrycount;
  142.  
  143.  
  144. /*  fold known accented letters to unaccented, other strange characters to space
  145.  *  apostrophe is among the exceptions to be kept (important for multi-word expressions)
  146.  */
  147. void deaccent2(char *p)
  148. {
  149.   char *sp;
  150.   char *v;
  151.   for(sp=p;*sp;sp++) {
  152.   if(*sp<0 && (v=strchr(acctab,*sp))!=NULL)
  153.     *sp=*(deatab+(v-acctab));
  154.   if(!isalnum(*sp) && strchr(",.&$+*",*sp)==0) *sp=' ';
  155.   else *sp=tolower(*sp);
  156.   }
  157. }
  158.  
  159. /*  translate everything non-alphanumeric into space */
  160. void towords(char *p)
  161. {
  162.   char *pp;
  163.   for(pp=p;*pp;pp++) if(!isalnum(*pp) && strchr("&$+*",*pp)==0) *pp=' ';
  164. }
  165.  
  166. /*  Find first occurrence of word */
  167. char *wordchr2(char *p, char *w)
  168. {
  169.   char *r;
  170.  
  171.   for(r=strstr(p,w);r!=NULL &&
  172.     ( (r>p && !isspace(*(r-1))) || (!isspace(*(r+strlen(w))) && *(r+strlen(w))!=0) );
  173.   r=strstr(r+1,w));
  174.   return r;
  175. }
  176.  
  177. char *find_tag_end(char *p)
  178. {
  179.   char *pp;
  180.   pp=p; if(*pp=='<') pp++;
  181.   for(; *pp && *pp!='>'; pp++) {
  182.     if(*pp=='<') {
  183.       pp=find_tag_end(pp)-1; continue;
  184.     }
  185.     if(*pp=='"') {
  186.       pp=strchr(pp+1,'"');
  187.       if(pp==NULL) return p+strlen(p); else continue;
  188.     }
  189.     if(*pp=='\'') {
  190.       pp=strchr(pp+1,'\'');
  191.       if(pp==NULL) return p+strlen(p); else continue;
  192.     }
  193.   }
  194.   if(*pp=='>') pp++;
  195.   return pp;
  196. }
  197.  
  198. char *find_tag(char *p, char *tag)
  199. {
  200.   char *pp;
  201.   int len;
  202.   len=strlen(tag);
  203.   for(pp=strchr(p,'<'); pp!=NULL && *pp; pp=strchr(pp+1,'<')) {
  204.     if(strncasecmp(pp+1,tag,len)==0 && !isalnum(*(pp+1+len))) return pp;
  205.   }
  206.   return p+strlen(p);
  207. }
  208.  
  209. /*  remove all html tags */
  210. void detag(char *p)
  211. {
  212.   char *pp, *p2;
  213.   for(pp=strchr(p,'<'); pp!=NULL; pp=strchr(pp,'<')) {
  214.     p2=find_tag_end(pp);
  215.     if(*p2==0) {*pp=0; return; }
  216.     ovlstrcpy(pp,p2);
  217.   }
  218. }
  219.  
  220. /* add a space after comma to see end of words */
  221.  
  222. void comma(char *p)
  223. {
  224.   char *pp;
  225.   for(pp=strchr(p,','); pp; pp=strchr(pp+1,','))
  226.     string_modify3(p,pp,pp+1,", ");
  227. }
  228. /* replace / by , */
  229. void backslash(char *p)
  230. {
  231.   char *pp;
  232.   for(pp=strchr(p,'/'); pp; pp=strchr(pp+1,'/'))
  233.     string_modify3(p,pp,pp+1,",");
  234. }
  235. /* _getdef from lines.c except the error msg*/
  236. void _getdef(char buf[], char *name, char value[])
  237. {
  238.   char *p1, *p2, *p3, *p4;
  239.  
  240.   if(*name==0) goto nothing;      /* this would create segfault. */
  241.   for(p1=strstr(buf,name); p1!=NULL; p1=strstr(p1+1,name)) {
  242.     p2=find_word_start(p1+strlen(name));
  243.     if((p1>buf && !isspace(*(p1-1))) || *p2!='=') continue;
  244.     p3=p1; while(p3>buf && *(p3-1)!='\n') p3--;
  245.     p3=find_word_start(p3);
  246.     if(p3<p1 && *p3!='!') continue;
  247.     if(p3<p1) {
  248.       p3++; p4=find_word_end(p3);
  249.       if(find_word_start(p4)!=p1) continue;
  250.       if(p4-p3!=3 || (strncmp(p3,"set",3)!=0 &&
  251.            strncmp(p3,"let",3)!=0 &&
  252.            strncmp(p3,"def",3)!=0)) {
  253.         if(p4-p3!=6 || strncmp(p3,"define",6)!=0) continue;
  254.       }
  255.     }
  256.     p2++;p3=strchr(p2,'\n'); if(p3==NULL) p3=p2+strlen(p2);
  257.     p2=find_word_start(p2);
  258.     if(p2>p3) goto nothing;
  259.     /*if(p3-p2>=MAX_LINELEN) user_error("cmd_output_too_long");*/
  260.     memmove(value,p2,p3-p2); value[p3-p2]=0;
  261.     strip_trailing_spaces(value); return;
  262.   }
  263. nothing:
  264.   value[0]=0;
  265. }
  266.  
  267. /*  Get variable definition from a file.
  268.  * Result stored in buffer value of length MAX_LINELEN.
  269.  */
  270. void getdef(char *fname, char *name, char value[])
  271. {
  272.   FILE *f;
  273.   char *buf;
  274.   int l;
  275.  
  276.   value[0]=0;
  277.   f=fopen(fname,"r"); if(f==NULL) return;
  278.   fseek(f,0,SEEK_END); l=ftell(f); fseek(f,0,SEEK_SET);
  279.   buf=xmalloc(l+256); l=fread(buf,1,l,f);
  280.   fclose(f);
  281.   if(l<=0) return; else buf[l]=0;
  282.   _getdef(buf,name,value);
  283.   free(buf);
  284. }
  285.  
  286. void init(void)
  287. {
  288.   char buf[MAX_LINELEN+1];
  289.   char *p1,*p2,*s;
  290.   int i,l;
  291.   FILE *f;
  292.  
  293.   s=getenv("modind_outdir"); if(s!=NULL && *s!=0) outdir=s;
  294.   s=getenv("modind_sheetdir"); if(s!=NULL && *s!=0) sheetdir=s;
  295.   s=getenv("modind_sheetoutdir"); if(s!=NULL && *s!=0) sheetoutdir=s;
  296.   s=getenv("modind_glossaryoutdir"); if(s!=NULL && *s!=0) glossaryoutdir=s;
  297. /* take the langs declared in conffile */
  298.   getdef(conffile,"site_languages",buf);
  299.   langcnt=0;
  300.   for(p1=buf;*p1;p1++) if(!isalnum(*p1)) *p1=' ';
  301.   for(p1=find_word_start(buf); *p1 && langcnt<MAX_LANGS; p1=find_word_start(p2)) {
  302.     p2=find_word_end(p1);
  303.     if(p2!=p1+2 || !isalpha(*p1) || !isalpha(*(p1+1))) continue;
  304.     memmove(lang[langcnt],p1,2); lang[langcnt++][2]=0;
  305.   }
  306.   if(langcnt==0) {/*  default languages */
  307.     langcnt=DEFAULT_LANGCNT;
  308.   }
  309.   for(i=0;i<langcnt;i++) {
  310.     snprintf(buf,sizeof(buf),"%s/%s.%s",dicdir,ignoredic,lang[i]);
  311.     f=fopen(buf,"r"); if(f==NULL) continue;
  312.     l=fread(ignore[i],1,MAX_LINELEN,f);fclose(f);
  313.     if(l<0 || l>=MAX_LINELEN) l=0;
  314.     ignore[i][l]=0;
  315.   }
  316. }
  317. /*  Preparation of data */
  318. void prep(void)
  319. {
  320.   char buf[MAX_LINELEN+1];
  321.   char *p1,*p2,*s,*old;
  322.   int i,l,thislang,t;
  323.   modcnt=0; old="";
  324.   snprintf(buf,sizeof(buf),"%s/addr",outdir);
  325.   addrf=fopen(buf,"w");
  326.   if(!addrf) { fprintf(stderr,"modind: error creating output files addr.\n"); exit(1);}
  327.   snprintf(buf,sizeof(buf),"%s/serial",outdir);
  328.   serialf=fopen(buf,"w");
  329.   if(!serialf) { fprintf(stderr,"modind: error creating output files serial.\n"); exit(1);}
  330.  
  331.   s=getenv("mlist"); if(s==NULL) exit(1);
  332.   l=strlen(s); if(l<0 || l>100*MAX_LINELEN) exit(1);
  333.   mlist=xmalloc(l+16); ovlstrcpy(mlist,s);
  334.  
  335.   for(t=0, p1=find_word_start(mlist); *p1 && modcnt<MAX_MODULES;
  336.         p1=find_word_start(p2), t++) {
  337.     p2=find_word_end(p1);
  338.     l=p2-p1; if(*p2) *p2++=0;
  339.     fprintf(addrf,"%d:%s\n",t,p1);
  340.     fprintf(serialf,"%s:%d\n",p1,t);
  341.     thislang=-1;
  342. /* language is taken from the address */
  343.     if(l>3 && p1[l-3]=='.') {
  344.       for(i=0;i<langcnt;i++) if(strcasecmp(lang[i],p1+l-2)==0) break;
  345.       if(i<langcnt) {p1[l-3]=0; thislang=i;}
  346.       else {/*  unknown language, not referenced */
  347.         continue;
  348.       }
  349.     }
  350.     if(modcnt>0 && strcmp(old,p1)==0 && thislang>=0) {
  351.       if(mod[modcnt-1].langcnt<langcnt) {
  352.         mod[modcnt-1].langs[mod[modcnt-1].langcnt]=thislang;
  353.         mod[modcnt-1].counts[mod[modcnt-1].langcnt]=t;
  354.         (mod[modcnt-1].langcnt)++;
  355.       }
  356.     }
  357.     else {
  358.       mod[modcnt].name=old=p1;
  359.       if(thislang>=0) {
  360.         mod[modcnt].langs[0]=thislang;
  361.         mod[modcnt].langcnt=1;
  362.       }
  363.       else mod[modcnt].langcnt=0;
  364.       mod[modcnt].counts[0]=t;
  365.       modcnt++;
  366.     }
  367.   }
  368.   snprintf(buf,sizeof(buf),"%s/language",outdir);
  369.   langf=fopen(buf,"w");
  370.   snprintf(buf,sizeof(buf),"%s/title",outdir);
  371.   titf=fopen(buf,"w");
  372.   snprintf(buf,sizeof(buf),"%s/description",outdir);
  373.   descf=fopen(buf,"w");
  374.   snprintf(buf,sizeof(buf),"%s/author",outdir);
  375.   authorf=fopen(buf,"w");
  376.   snprintf(buf,sizeof(buf),"%s/version",outdir);
  377.   versionf=fopen(buf,"w");
  378.   snprintf(buf,sizeof(buf),"%s/%s/robot.phtml",outdir,mlistbase);
  379.   robotf=fopen(buf,"w");
  380.   fclose(addrf); fclose(serialf);
  381.   if(!robotf || !versionf || !authorf || !descf || !titf || !langf) {
  382.     fprintf(stderr,"modind: error creating output files.\n");
  383.     exit(1);
  384.   }
  385. }
  386.  
  387. void sprep(void)
  388. {
  389.   char buf[MAX_LINELEN+1];
  390.   char *p1,*p2,*s;
  391.   int i,l,t,thislang;
  392.  
  393.   modcnt=0;
  394.   snprintf(buf,sizeof(buf),"%s/addr",sheetoutdir);
  395.   addrf=fopen(buf,"w");
  396.   if(!addrf) { fprintf(stderr,"modind: error creating output files addr.\n"); exit(1);}
  397.   snprintf(buf,sizeof(buf),"%s/serial",sheetoutdir);
  398.   serialf=fopen(buf,"w");
  399.   s=getenv("slist"); if(s==NULL) return;
  400.   l=strlen(s); if(l<0 || l>100*MAX_LINELEN) return;
  401.   mlist=xmalloc(l+16); ovlstrcpy(mlist,s);
  402.   for(t=0,p1=find_word_start(mlist); *p1 && modcnt<MAX_MODULES; p1=find_word_start(p2),t++) {
  403.     p2=find_word_end(p1);
  404.     l=p2-p1; if(*p2) *p2++=0;
  405.     for(i=0;i<langcnt;i++) if(strncasecmp(lang[i],p1,2)==0) break;
  406.     if(i<langcnt) thislang=i; else continue;
  407.     ovlstrcpy(revmod[t].name,p1);
  408.     revmod[t].lang=thislang;
  409.     mod[modcnt].name=p1;
  410.     mod[modcnt].langs[0]=thislang;
  411.     mod[modcnt].langcnt=1;
  412.     revmod[t].imod=modcnt;
  413.     fprintf(addrf,"%d:%s\n",modcnt,p1);
  414.     fprintf(serialf,"%s:%d\n",p1,modcnt);
  415.     modcnt++;
  416.   }
  417.  fclose(addrf); fclose(serialf);
  418. }
  419.  
  420. void gprep(void)
  421. {
  422.   char buf[MAX_LINELEN+1];
  423.   char *p1,*p2,*s,*old;
  424.   int l,i,t,thislang;
  425.   modcnt=0; old="";
  426.   snprintf(buf,sizeof(buf),"%s/addr",glossaryoutdir);
  427.   addrf=fopen(buf,"w");
  428.   if(!addrf) { fprintf(stderr,"modind: error creating output files addr.\n"); exit(1);}
  429.   snprintf(buf,sizeof(buf),"%s/serial",glossaryoutdir);
  430.   serialf=fopen(buf,"w");
  431.   s=getenv("glist"); if(s==NULL) return;
  432.   l=strlen(s); if(l<0 || l>100*MAX_LINELEN) return;
  433.   mlist=xmalloc(l+16); ovlstrcpy(mlist,s);
  434.   for(t=0,p1=find_word_start(mlist); *p1 && modcnt<MAX_MODULES; p1=find_word_start(p2),t++) {
  435.     p2=find_word_end(p1);
  436.     if(*p2) *p2++=0;
  437.     fprintf(addrf,"%d:%s\n",t,p1);
  438.     fprintf(serialf,"%s:%d\n",p1,t);
  439.     ovlstrcpy(revmod[t].name,p1);
  440.     ovlstrcpy(revmod[t].keywords,p1);
  441.     s=strchr(p1,'/');
  442.     if(s != NULL) s=strchr(s+1,'/');
  443.     if(s==NULL) {
  444.       fprintf(stderr,"modind: no language %s\n",p1); exit(1);
  445.     }
  446.     revmod[t].keywords[s-p1]=0;
  447.     s++;
  448.     for(i=0;i<langcnt;i++) if(strncasecmp(lang[i],s,2)==0) break;
  449.     thislang = i<langcnt ? i : -1;
  450.     revmod[t].lang=i;
  451.     s[0]=s[1]='x';
  452.     if(modcnt>0 && strcmp(old,p1)==0 && thislang >= 0) {
  453.       if(mod[modcnt-1].langcnt<langcnt) {
  454.         mod[modcnt-1].langs[mod[modcnt-1].langcnt]=thislang;
  455.         mod[modcnt-1].counts[mod[modcnt-1].langcnt]=t;
  456.         (mod[modcnt-1].langcnt)++;
  457.       }
  458.       revmod[t].imod=modcnt-1;
  459.     }
  460.     else {
  461.       mod[modcnt].name=old=p1;
  462.       if(thislang>=0) {
  463.         mod[modcnt].langs[0]=thislang;
  464.         mod[modcnt].langcnt=1;
  465.       }
  466.       else mod[modcnt].langcnt=0;
  467.       mod[modcnt].counts[0]=t;
  468.       revmod[t].imod=modcnt;
  469.       modcnt++;
  470.     }
  471.   }
  472.   fclose(addrf); fclose(serialf);
  473. }
  474.  
  475. /*  read and treat module's INDEX file */
  476. int module_index(const char *name)
  477. {
  478.   char *p, fbuf[MAX_LINELEN+1], ibuf[MAX_LINELEN+1];
  479.   FILE *indf;
  480.   int i,l;
  481.  
  482.   snprintf(fbuf,sizeof(fbuf),"%s/%s/INDEX",moduledir,name);
  483.   indf=fopen(fbuf,"r");
  484.   if(indf==NULL) {
  485.     fprintf(stderr,"modind: INDEX of %s not found\n",fbuf); return -1;
  486.   }
  487.   l=fread(ibuf,1,MAX_LINELEN,indf); fclose(indf);
  488.   if(l>0 && l<MAX_LINELEN) ibuf[l]=0; else return -1;
  489. /* treate all fields in *modindex */
  490.   for(i=0;i<MODINDEX_NO;i++) {
  491.     _getdef(ibuf,modindex[i],indbuf[i]);
  492. /*  compatibility precaution */
  493.     if(indbuf[i][0]==':') indbuf[i][0]='.';
  494.   }
  495.   p=find_word_start(indbuf[i_language]);
  496.   if(isalpha(*p) && isalpha(*(p+1))) {
  497.     memmove(module_language,p,2); module_language[2]=0;
  498.   }
  499.   else ovlstrcpy(module_language,"en");
  500.   return 0;
  501. }
  502.  
  503. int sheet_index(int serial)
  504. {
  505.   char *p1, *p2, fbuf[MAX_LINELEN+1], ibuf[MAX_LINELEN+1];
  506.   FILE *indf;
  507.   int i,l;
  508.  
  509.   snprintf(fbuf,sizeof(fbuf),"%s/%s.def",sheetdir,mod[serial].name);
  510.   indf=fopen(fbuf,"r"); if(indf==NULL) return -1;
  511.   l=fread(ibuf,1,MAX_LINELEN,indf); fclose(indf);
  512.   if(l>0 && l<MAX_LINELEN) ibuf[l]=0; else return -1;
  513.   for(i=0;i<SHEETINDEX_NO;i++) gsindbuf[i][0]=0;
  514.   for(i=0,p1=find_word_start(ibuf);
  515.       i<SHEETINDEX_NO-1 && *p1!=':' && *p1!=0;
  516.       i++,p1=p2) {
  517.     p2=strchr(p1,'\n');
  518.     if(p2!=NULL) *p2++=0; else p2=p1+strlen(p1);
  519.     p1=find_word_start(p1); strip_trailing_spaces2(p1);
  520.     snprintf(gsindbuf[i],MAX_LINELEN,"%s",p1);
  521.   }
  522.   p2=strstr(p1,"\n:"); if(p2==NULL) p2=p1+strlen(p1);
  523.   else *p2=0;
  524.   p1=find_word_start(p1); strip_trailing_spaces2(p1);
  525.   for(p2=p1;*p2;p2++) if(*p2=='\n') *p2=' ';
  526.   ovlstrcpy(gsindbuf[s_information],p1);
  527.   ovlstrcpy(gsindbuf[SHEETINDEX_NO],revmod[serial].name);
  528.   return 0;
  529. }
  530.  
  531. int glossary_index(int serial)
  532. {
  533.   char nbuf[MAX_LINELEN+1],fbuf[MAX_LINELEN+1], ibuf[MAX_LINELEN+1],*p,*s;
  534.   FILE *indf;
  535.   int i,l;
  536.   s=lang[revmod[serial].lang];
  537.   p=strchr(nbuf,'/');
  538.   if(p != NULL) p=strchr(p+1,'/');
  539.   if(p != NULL) {p[1]=s[0];p[2]=s[1];}
  540.   snprintf(fbuf,sizeof(fbuf),"%s/%s",glossarydir,revmod[serial].name);
  541.   indf=fopen(fbuf,"r");
  542.   l=fread(ibuf,1,MAX_LINELEN,indf); fclose(indf);
  543.   if(l>0 && l<MAX_LINELEN) ibuf[l]=0; else return -1;
  544.   for(i=0;i<SHEETINDEX_NO;i++) {
  545.     _getdef(ibuf,glindex[i],gsindbuf[i]);
  546.   }
  547.   s=gsindbuf[s_keywords]+strlen(gsindbuf[s_keywords]);
  548.   *s++ = ',';
  549.   ovlstrcpy(s,revmod[serial].keywords);
  550.   backslash(revmod[serial].keywords);
  551.   ovlstrcpy(gsindbuf[SHEETINDEX_NO],nbuf);
  552.   return 0;
  553. }
  554.  
  555. unsigned char categories[16];
  556. char taken[MAX_LINELEN+1];
  557. int catcnt, takenlen, tweight;
  558.  
  559. /* file management for appenditem */
  560. #define MAX_FILES (MAX_LANGS*catno)
  561.  
  562. char *fnames[MAX_FILES];
  563. FILE *files[MAX_FILES];
  564. int open_files;
  565.  
  566. FILE * file_from_list(char *name){
  567.   int i, l = 0, r = open_files;
  568.   while (r>l){
  569.     int m = (l+r)/2;
  570.     int cmp = strcmp(name,fnames[m]);
  571.     if (!cmp) return files[m];
  572.     if (cmp < 0) r = m; else l = m+1;
  573.   }
  574.   for (i=open_files; i > l; i--) {files[i]=files[i-1]; fnames[i]=fnames[i-1];}
  575.   fnames[l] = xmalloc(MAX_FNAME);
  576.   ovlstrcpy(fnames[l],name);
  577.   open_files++;
  578.   return files[l]=fopen(name,"a");
  579. }
  580.  
  581. void appenditem(char *word, int lind, int serial, int weight, char *l)
  582. {
  583.   char nbuf[MAX_LINELEN+1], buf[MAX_LINELEN+1];
  584.   int i, ll;
  585.   char *p;
  586.   FILE *f;
  587.  
  588.   if(!isalnum(*word) || (ll=strlen(word))<2 ||
  589.      wordchr2(taken,word)!=NULL ||
  590.      wordchr2(ignore[lind],word)!=NULL ||
  591.      takenlen>=MAX_LINELEN-ll-16)
  592.     return;
  593.   if(ll==2 && (!isdigit(word[0]) || !isalpha(word[1]))) return;
  594.   for(p=word;*p;p++) if(!isalnum(*p) && *p!=' ') return;
  595.   taken[takenlen++]=' '; taken[takenlen++]=' ';
  596.   ovlstrcpy(taken+takenlen,word);
  597.   takenlen+=ll; tweight+=weight;
  598.   snprintf(buf,sizeof(buf),"%s:%d?%d\n",word,serial,weight);
  599.   for(i=0;i<catcnt;i++) {
  600.     snprintf(nbuf,sizeof(nbuf),"%s/%c.%s",
  601.        outdir,categories[i],lang[lind]);
  602.     f = file_from_list(nbuf);
  603.     if(f!=NULL) {fputs(buf,f);}
  604.   }
  605. }
  606.  
  607. void appenditem1 (char *buf, int lind, int serial, int weight, char *l )
  608. {
  609.   char *p1, *p2 ;
  610.   for(p1=find_word_start(buf); *p1;
  611.     p1=find_word_start(p2)) {
  612.     p2=strchr(p1,',');
  613.     if(p2!=NULL) *p2++=0; else p2=p1+strlen(p1);
  614.     if(strlen(p1)<=0) continue;
  615.     appenditem(p1,lind,serial,weight,module_language);
  616.   }
  617. }
  618. void appenditem2 (char *buf, int lind, int serial, int weight, char *l )
  619. {
  620.   char *p1, *p2 ;
  621.   for(p1=find_word_start(buf);*p1;
  622.       p1=find_word_start(p2)) {
  623.     p2=find_word_end(p1); if(*p2) *p2++=0;
  624.     appenditem(p1,lind,serial,weight,module_language);
  625.   }
  626. }
  627. void onemodule(const char *name, int serial, int lind)
  628. {
  629.   int i;
  630.   unsigned char trlist[]={
  631.   i_title,i_description,i_category,i_domain,i_keywords,
  632.   i_require,i_author,
  633.   i_keywords_ca,i_keywords_en,i_keywords_fr,i_keywords_it,i_keywords_nl,
  634.   i_title_ca,i_title_en,i_title_fr,i_title_it,i_title_nl
  635.   };
  636.   int trcnt=sizeof(trlist)/sizeof(trlist[0]);
  637.   char *p1, *p2, *pp, *q, buf[15*MAX_LINELEN+15], lbuf[16];
  638.   FILE *f;
  639.  
  640.   if(module_index(name)) return;
  641.   towords(indbuf[i_category]);
  642. /*   list the categories (among A=all,X=eXercise,O,D,...) corresponding
  643.  *   to this module
  644.  */
  645.   for(i=catcnt=0;i<catno && catcnt<16;i++) {
  646.     if(wordchr2(indbuf[i_category],cat[i].name)!=NULL)
  647.       categories[catcnt++]=cat[i].typ;
  648.   }
  649.   if(catcnt==0) return;
  650.   if(categories[0]!=cat[0].typ)
  651.     categories[catcnt++]=cat[0].typ;
  652. /*  write module's name in the category.language files, for instance lists/X.fr
  653.  * for french exercises
  654.  */
  655.   for(i=0;i<catcnt;i++) {
  656.     snprintf(buf,sizeof(buf),"%s/%s/%c.%s",
  657.        outdir,mlistbase,categories[i],lang[lind]);
  658.     f=fopen(buf,"a");
  659.     if(f!=NULL) {fprintf(f,"%s\n",name); fclose(f);}
  660.   }
  661. /*   add serial number and language (resp.title, ...) to corresponding file  */
  662.   fprintf(langf,"%d:%s\n",serial,module_language);
  663.   fprintf(titf,"%d:%s\n",serial,indbuf[i_title]);
  664.   fprintf(descf,"%d:%s\n",serial,indbuf[i_description]);
  665.   fprintf(authorf,"%d:%s\n",serial,indbuf[i_author]);
  666.   fprintf(versionf,"%d:%s\n",serial,indbuf[i_version]);
  667.  
  668. /*   add module's information in html page for robots  */
  669.   snprintf(buf,sizeof(buf),"%s",indbuf[i_description]);
  670.   for(pp=strchr(buf,','); pp; pp=strchr(pp,','))
  671.     string_modify3(buf,pp,pp+1,"&#44;");
  672.   if(strcmp(module_language,lang[lind])==0)
  673.     fprintf(robotf,"%s ,%s,%s,%s,%s\n",name,module_language,name,
  674.         indbuf[i_title], buf);
  675.  
  676. /*   Normalize the information of trlist, using dictionary
  677.  *  -- bases/sys/domain.xx without suffix translation (--> english version)
  678.  */
  679.   entrycount=dentrycount; dicbuf=ddicbuf;
  680.   memmove(entry,dentry,dentrycount*sizeof(entry[0]));
  681.   unknown_type=unk_leave;
  682.   for(i=0;i<trcnt;i++) {
  683.     detag(indbuf[trlist[i]]);
  684.     deaccent2(indbuf[trlist[i]]);
  685.     comma(indbuf[trlist[i]]);
  686.     singlespace2(indbuf[trlist[i]]);
  687.     translate(indbuf[trlist[i]]);
  688.   }
  689. /*   Normalize the information, using dictionary
  690.  *   bases/sys/words.xx with suffix translation
  691.  */
  692.   entrycount=mentrycount; dicbuf=mdicbuf;
  693.   memmove(entry,mentry,mentrycount*sizeof(entry[0]));
  694.   unknown_type=unk_leave;/*  used in translator_.c */
  695.   for(i=0;i<trcnt;i++) {
  696.   suffix_translate(indbuf[trlist[i]]);
  697.   translate(indbuf[trlist[i]]);
  698.   }
  699.  
  700. /* taken contains all words already seen in the module index */
  701.   taken[0]=0; takenlen=tweight=0;
  702. /*  append words of title  */
  703.   ovlstrcpy(buf,indbuf[i_title]); towords(buf);
  704.   appenditem2(buf,lind,serial,4,module_language);
  705.  
  706. /*  extract words of every other information except level */
  707.   snprintf(buf,sizeof(buf),"%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
  708.     indbuf[i_description],indbuf[i_keywords],
  709.     indbuf[i_keywords_ca],indbuf[i_keywords_en],indbuf[i_keywords_fr],
  710.     indbuf[i_keywords_it],indbuf[i_keywords_nl],
  711.     indbuf[i_title_ca],indbuf[i_title_en],indbuf[i_title_fr],
  712.     indbuf[i_title_it],indbuf[i_title_nl],
  713.     indbuf[i_domain],indbuf[i_require],indbuf[i_author]);
  714.   towords(buf);
  715.   appenditem2(buf,lind,serial,2,module_language);
  716.  
  717. /*   this time the dictionary is the group dictionary  sys/wgrp/wgrp
  718.  *   with a g (groupdic), not an m (maindic) . see below main, suffix, group.
  719.  *   and delete unknown ?? and translate
  720.  */
  721.   entrycount=gentrycount; dicbuf=gdicbuf;
  722.   memmove(entry,gentry,gentrycount*sizeof(entry[0]));
  723.  
  724. /* append words of every title information  */
  725.   ovlstrcpy(buf,indbuf[i_title]);
  726.   unknown_type=unk_delete;
  727.   translate(buf);
  728.   appenditem1(buf,lind,serial,2,module_language);
  729.  
  730. /* append words of information of description except level  */
  731.   snprintf(buf,sizeof(buf),"%s", indbuf[i_description]);
  732.   unknown_type=unk_delete;
  733.   translate(buf);
  734.   appenditem1(buf,lind,serial,4,module_language);
  735.  
  736. /* append words (or group of words) of keywords and domain  */
  737.   snprintf(buf,sizeof(buf),"%s, %s, %s, %s, %s, %s, %s",
  738.     indbuf[i_domain],indbuf[i_keywords],
  739.     indbuf[i_keywords_ca], indbuf[i_keywords_en],indbuf[i_keywords_fr],
  740.     indbuf[i_keywords_it], indbuf[i_keywords_nl]);
  741.   unknown_type=unk_leave;
  742.   translate(buf);
  743.   appenditem1(buf,lind,serial,2,module_language);
  744.  
  745. /* append level information, with weight 2 */
  746.   snprintf(buf,sizeof(buf),"%s",indbuf[i_level]);
  747.   ovlstrcpy(lbuf,"level");
  748.   for(p1=buf; *p1; p1++) if(!isalnum(*p1)) *p1=' ';
  749.   q=buf+strlen(buf);
  750.   for(p1=find_word_start(buf); (*p1) && (p1 < q) ; p1=find_word_start(p2)) {
  751.     p2=find_word_end(p1);
  752.     if(p2!=NULL) *p2++=0; else p2=p1+strlen(p1);
  753.     if(strncmp(p1, "Lang" , p2-p1) &&
  754.      (!isalpha(*p1) ||
  755.      (!isdigit(*(p1+1)) && *(p1+1)!=0) ||
  756.      (*(p1+1)!=0 && *(p1+2)!=0)))
  757.        continue;
  758.     *p1=tolower(*p1);
  759.     ovlstrcpy(lbuf+strlen("level"),p1);
  760.     appenditem(lbuf,lind,serial,2,module_language);
  761.   }
  762. /*   append total weight of module to weight file site2/weight.xx  */
  763.   fprintf(weightf,"%d:%d\n",serial,tweight);
  764. }
  765.  
  766. void modules(void)
  767. {
  768.   int i,j,k,d;
  769.   char namebuf[MAX_LINELEN+1];
  770.   char mdic[MAX_LINELEN+1], sdic[MAX_LINELEN+1], gdic[MAX_LINELEN+1], ddic[MAX_LINELEN+1];
  771.  
  772.   for(j=0;j<langcnt;j++) {
  773.     snprintf(namebuf,sizeof(namebuf),"%s/weight.%s",outdir,lang[j]);
  774.     weightf=fopen(namebuf,"w");
  775.     snprintf(mdic,sizeof(mdic),"%s/%s.%s",dicdir,maindic,lang[j]);
  776.     snprintf(sdic,sizeof(sdic),"%s/%s.%s",dicdir,suffixdic,lang[j]);
  777.     snprintf(gdic,sizeof(gdic),"%s/%s.%s",dicdir,groupdic,lang[j]);
  778.     snprintf(ddic,sizeof(ddic),"%s/%s.%s",dicdir,domaindic,lang[j]);
  779.     suffix_dic(sdic); prepare_dic(gdic);
  780.     gdicbuf=dicbuf; gentrycount=entrycount;
  781.     memmove(gentry,entry,gentrycount*sizeof(entry[0]));
  782.     prepare_dic(mdic);
  783.     mdicbuf=dicbuf; mentrycount=entrycount;
  784.     memmove(mentry,entry,mentrycount*sizeof(entry[0]));
  785.     prepare_dic(ddic);
  786.     ddicbuf=dicbuf; dentrycount=entrycount;
  787.     memmove(dentry,entry,dentrycount*sizeof(entry[0]));
  788.     unknown_type=unk_leave; translate(ignore[j]);
  789.     for(i=0;i<modcnt;i++) {
  790.       if(mod[i].langcnt>0) {
  791.       /* look for another language */
  792.         for(d=k=0;k<mod[i].langcnt;k++)
  793.           if(mod[i].langs[k]<mod[i].langs[d]) d=k;
  794.         for(k=0;k<mod[i].langcnt && mod[i].langs[k]!=j;k++);
  795.         if(k>=mod[i].langcnt) k=d;
  796.         snprintf(namebuf,MAX_LINELEN,"%s.%s",mod[i].name,
  797.            lang[mod[i].langs[k]]);
  798.         onemodule(namebuf,mod[i].counts[k],j);
  799.       }
  800.       else {
  801.         onemodule(mod[i].name,mod[i].counts[0],j);
  802.       }
  803.     }
  804.     if(mentrycount>0) free(mdicbuf);
  805.     if(gentrycount>0) free(gdicbuf);
  806.     if(suffixcnt>0) free(sufbuf);
  807.     if(dentrycount>0) free(ddicbuf);
  808.     if(weightf) fclose(weightf);
  809.   }
  810. }
  811. void clean(void)
  812. {
  813.   int i;
  814.   for (i = 0; i < open_files; i++) fclose(files[i]);
  815.   fclose(langf); fclose(titf); fclose(descf); fclose(robotf);
  816.   fclose(authorf); fclose(versionf);
  817. }
  818.  
  819. /* FIXME ? differences with appenditem - use fprintf instead of  snprintf */
  820. void sappenditem(char *word, int lind, int serial, int weight)
  821. {
  822.   int ll;
  823.   char *p;
  824.  
  825.   if(!isalnum(*word) || (ll=strlen(word))<2 ||
  826.      wordchr2(taken,word)!=NULL ||
  827.      wordchr2(ignore[lind],word)!=NULL ||
  828.      takenlen>=MAX_LINELEN-ll-16)
  829.     return;
  830.   if(ll==2 && (!isdigit(word[0]) || !isalpha(word[1]))) return;
  831.   for(p=word;*p;p++) if(!isalnum(*p) && *p!=' ') return;
  832.   taken[takenlen++]=' ';taken[takenlen++]=' ';
  833.   ovlstrcpy(taken+takenlen,word);
  834.   takenlen+=ll; tweight+=weight;
  835.   fprintf(indf,"%s:%d?%d\n",word,serial,weight);
  836. }
  837. /* onesg / onemodule are similar */
  838. void onesg(int serial, int lind, int index(int))
  839. {
  840.   int i;
  841.   unsigned char trlist[]={
  842.     s_title,s_description,s_domain,s_keywords,s_information
  843.   };
  844.   int trcnt=sizeof(trlist)/sizeof(trlist[0]);
  845.   char *p1, *p2, *q, buf[4*MAX_LINELEN+4], lbuf[16];
  846.  
  847.   if(index(serial)) return;
  848.   fprintf(titf,"%d:%s\n",serial,gsindbuf[s_title]);
  849.   fprintf(descf,"%d:%s\n",serial,gsindbuf[s_description]);
  850.   fprintf(remf,"%d:%s\n",serial,gsindbuf[s_information]);
  851.  
  852. /*   Normalize the information of trlist, using dictionary
  853.  *  -- bases/sys/domain.xx without suffix translation (--> english version)
  854.  */
  855.   entrycount=dentrycount; dicbuf=ddicbuf;
  856.   memmove(entry,dentry,dentrycount*sizeof(entry[0]));
  857.   unknown_type=unk_leave;
  858.   for(i=0;i<trcnt;i++) {
  859.     detag(gsindbuf[trlist[i]]);
  860.     deaccent2(gsindbuf[trlist[i]]);
  861.     comma(gsindbuf[trlist[i]]);
  862.     singlespace2(gsindbuf[trlist[i]]);
  863.     translate(gsindbuf[trlist[i]]);
  864.   }
  865. /*   Normalize the information, using dictionary
  866.  *   bases/sys/words.xx with suffix translation
  867.  */
  868.   entrycount=mentrycount; dicbuf=mdicbuf;
  869.   memmove(entry,mentry,mentrycount*sizeof(entry[0]));
  870.   unknown_type=unk_leave;/*  used in translator_.c */
  871.   for(i=0;i<trcnt;i++) {
  872.     suffix_translate(gsindbuf[trlist[i]]);
  873.     translate(gsindbuf[trlist[i]]);
  874.   }
  875.  
  876. /* taken contains all words already seen in the module index */
  877.   taken[0]=0; takenlen=tweight=0;
  878. /*  append words of title  */
  879.   ovlstrcpy(buf,gsindbuf[s_title]); towords(buf);
  880.   for(p1=find_word_start(buf);*p1;
  881.       p1=find_word_start(p2)) {
  882.     p2=find_word_end(p1); if(*p2) *p2++=0;
  883.     sappenditem(p1,lind,serial,4);
  884.   }
  885.  
  886. /*  extract words of every other information except level */
  887.   snprintf(buf,sizeof(buf),"%s %s %s %s",
  888.          gsindbuf[s_description],gsindbuf[s_keywords],
  889.          gsindbuf[s_domain],gsindbuf[s_information]);
  890.   towords(buf);
  891.   for(p1=find_word_start(buf);*p1;p1=find_word_start(p2)) {
  892.     p2=find_word_end(p1); if(*p2) *p2++=0;
  893.     sappenditem(p1,lind,serial,2);
  894.   }
  895. /*   this time the dictionary is the group dictionary  sys/wgrp/wgrp
  896.  *   with a g (groupdic), not an m (maindic) . see below main, suffix, group.
  897.  *   and delete unknown ?? and translate
  898.  */
  899.   entrycount=gentrycount; dicbuf=gdicbuf;
  900.   memmove(entry,gentry,gentrycount*sizeof(entry[0]));
  901.  
  902. /*  append words of every title information  */
  903.   ovlstrcpy(buf,gsindbuf[s_title]);
  904.   unknown_type=unk_delete;
  905.   translate(buf);
  906.   for(p1=find_word_start(buf); *p1; p1=find_word_start(p2)) {
  907.     p2=strchr(p1,',');
  908.     if(p2!=NULL) *p2++=0; else p2=p1+strlen(p1);
  909.     if(strlen(p1)<=0) continue;
  910.     sappenditem(p1,lind,serial,4);
  911.   }
  912.  
  913. /*  append words (or group of words) of keywords and domain  */
  914.   snprintf(buf,sizeof(buf),"%s, %s",
  915.        gsindbuf[s_keywords],
  916.        gsindbuf[s_domain]);
  917.   unknown_type=unk_leave;
  918.   translate(buf);
  919.   for(p1=find_word_start(buf); *p1; p1=find_word_start(p2)) {
  920.     p2=strchr(p1,',');
  921.     if(p2!=NULL) *p2++=0; else p2=p1+strlen(p1);
  922.     if(strlen(p1)<=0) continue;
  923.     sappenditem(p1,lind,serial,2);
  924.   }
  925.  
  926. /*   append level information, with weight 2 */
  927.   snprintf(buf,sizeof(buf),"%s",gsindbuf[s_level]);
  928.   ovlstrcpy(lbuf,"level");
  929.   for(p1=buf; *p1; p1++) if(!isalnum(*p1)) *p1=' ';
  930.   q=buf+strlen(buf);
  931.   for(p1=find_word_start(buf); (*p1) && (p1 < q) ;
  932.   p1=find_word_start(p2)) {
  933.     p2=find_word_end(p1);
  934.     if(p2!=NULL) *p2++=0; else p2=p1+strlen(p1);
  935.     if(strncmp(p1, "Lang" , p2-p1) &&
  936.         (!isalpha(*p1) || (!isdigit(*(p1+1))) ||
  937.         (*(p1+1)!=0 && *(p1+2)!=0)))
  938.       continue;
  939.     *p1=tolower(*p1);
  940.     ovlstrcpy(lbuf+strlen("level"),p1);
  941.     sappenditem(lbuf,lind,serial,2);
  942.   }
  943. /*   append total weight of module to weight file site2/weight.xx  */
  944.   fprintf(weightf,"%d:%d\n",serial,tweight);
  945. }
  946.  
  947. void sgs(char *outdir, int index(int))
  948. {
  949.   int i,j,k,d;
  950.   char mdic[MAX_LINELEN+1], sdic[MAX_LINELEN+1], gdic[MAX_LINELEN+1], ddic[MAX_LINELEN+1];
  951.   char buf[MAX_LINELEN+1];
  952.  
  953.   //snprintf(buf,sizeof(buf),"%s/list",outdir);
  954.   //listf=fopen(buf,"w");
  955.   snprintf(buf,sizeof(buf),"%s/title",outdir);
  956.   titf=fopen(buf,"w");
  957.   snprintf(buf,sizeof(buf),"%s/description",outdir);
  958.   descf=fopen(buf,"w");
  959.   snprintf(buf,sizeof(buf),"%s/information",outdir);
  960.   remf=fopen(buf,"w");
  961.   if(!remf || !descf || !titf ) {
  962.     fprintf(stderr,"modind: error creating output files for %s.\n",outdir); exit(1);
  963.   }
  964.   for(j=0;j<langcnt;j++) {
  965.     snprintf(buf,sizeof(buf),"%s/%s",outdir,lang[j]);
  966.     indf=fopen(buf,"w");
  967.     snprintf(buf,sizeof(buf),"%s/weight.%s",outdir,lang[j]);
  968.     weightf=fopen(buf,"w");
  969.     if(!weightf || !indf ) {
  970.       fprintf(stderr,"modind: error creating output files for %s.\n",outdir); exit(1);
  971.     }
  972.     snprintf(mdic,sizeof(mdic),"%s/%s.%s",dicdir,maindic,lang[j]);
  973.     snprintf(sdic,sizeof(sdic),"%s/%s.%s",dicdir,suffixdic,lang[j]);
  974.     snprintf(gdic,sizeof(gdic),"%s/%s.%s",dicdir,groupdic,lang[j]);
  975.     snprintf(ddic,sizeof(ddic),"%s/%s.%s",dicdir,domaindic,lang[j]);
  976.     suffix_dic(sdic); prepare_dic(gdic);
  977.     gdicbuf=dicbuf; gentrycount=entrycount;
  978.     memmove(gentry,entry,gentrycount*sizeof(entry[0]));
  979.     prepare_dic(mdic);
  980.     mdicbuf=dicbuf; mentrycount=entrycount;
  981.     memmove(mentry,entry,mentrycount*sizeof(entry[0]));
  982.     prepare_dic(ddic);
  983.     ddicbuf=dicbuf; dentrycount=entrycount;
  984.     memmove(dentry,entry,dentrycount*sizeof(entry[0]));
  985.     unknown_type=unk_leave; translate(ignore[j]);
  986.     for(i=0;i<modcnt;i++)
  987.       if(mod[i].langcnt>0) {
  988.       /* look for another language */
  989.         for(d=k=0;k<mod[i].langcnt;k++)
  990.           if(mod[i].langs[k]<mod[i].langs[d]) d=k;
  991.         for(k=0;k<mod[i].langcnt && mod[i].langs[k]!=j;k++);
  992.         if(k>=mod[i].langcnt) k=d;
  993.         onesg(mod[i].counts[k],mod[i].langs[k],index);
  994.       }
  995.     if(mentrycount>0) free(mdicbuf);
  996.     if(gentrycount>0) free(gdicbuf);
  997.     if(suffixcnt>0) free(sufbuf);
  998.     if(dentrycount>0) free(ddicbuf);
  999.     fclose(indf); fclose(weightf);
  1000.   }
  1001.   fclose(titf); fclose(descf); fclose(remf);
  1002. }
  1003.  
  1004. int main()
  1005. {
  1006.   gentry=xmalloc(entry_size);
  1007.   dentry=xmalloc(entry_size);
  1008.   mentry=xmalloc(entry_size);
  1009.   init();
  1010.   prep();
  1011.   if(modcnt>0) modules();
  1012.   clean();
  1013.   sprep();
  1014.   if(modcnt>0) sgs(sheetoutdir,sheet_index);
  1015.   gprep();
  1016.   if(modcnt>0) sgs(glossaryoutdir,glossary_index);
  1017.   return 0;
  1018. }
  1019.