Julius 4.1.5
julius/module.c
00001 #include "app.h"
00002 
00003 #include <stdarg.h>
00004 
00005 #define DEFAULT_MODULEPORT 10500
00006 
00007 static int module_mode = FALSE;
00008 static int module_port = DEFAULT_MODULEPORT;
00009 int module_sd = -1;
00010 static FILE *module_fp;
00011 static RecogProcess *cur = NULL;
00012 
00013 #define MAXBUFLEN 4096 ///< Maximum line length of a message sent from a client
00014 static char mbuf[MAXBUFLEN];    
00015 static char buf[MAXBUFLEN];     
00016 static char inbuf[MAXBUFLEN];
00017 #ifdef CHARACTER_CONVERSION
00018 static char outbuf[MAXBUFLEN];
00019 #endif
00020 
00030 int
00031 module_send(int sd, char *fmt, ...)
00032 {
00033   va_list ap;
00034   int ret;
00035   char *buf;
00036   
00037   va_start(ap,fmt);
00038   ret = vsnprintf(inbuf, MAXBUFLEN, fmt, ap);
00039   va_end(ap);
00040   if (ret > 0) {                /* success */
00041     
00042 #ifdef CHARACTER_CONVERSION
00043     buf = charconv(inbuf, outbuf, MAXBUFLEN);
00044 #else
00045     buf = inbuf;
00046 #endif
00047     if (
00048 #ifdef WINSOCK
00049         send(sd, buf, strlen(buf), 0)
00050 #else
00051         write(sd, buf, strlen(buf))
00052 #endif
00053         < 0) {
00054       perror("Error: module_send:");
00055     }
00056   }
00057   return(ret);
00058 }
00059 
00060 static char *
00061 myfgets(char *buf, int maxlen, FILE *fp)
00062 {
00063   char *ret;
00064   int len;
00065   
00066   if ((ret = fgets(buf, maxlen, fp)) != NULL) {
00067     len = strlen(buf);
00068     if (buf[len-1] == '\n') {
00069       buf[len-1] = '\0';
00070       if (len >= 2 && buf[len-2] == '\r') {
00071         buf[len-2] = '\0';
00072       }
00073     }
00074   }
00075   return ret;
00076 }
00077 
00090 static boolean
00091 read_grammar(FILE *fp, DFA_INFO **ret_dfa, WORD_INFO **ret_winfo, HTK_HMM_INFO *hmminfo, RecogProcess *r)
00092 {
00093   DFA_INFO *dfa = NULL;
00094   WORD_INFO *winfo;
00095   JCONF_LM *lmconf;
00096 
00097   /* load grammar: dfa and dict in turn */
00098   if (r->lmvar != LM_DFA_WORD) {
00099     dfa = dfa_info_new();
00100     if (!rddfa_fp(fp, dfa)) {
00101       return FALSE;
00102     }
00103   }
00104   winfo = word_info_new();
00105   if (r->lmvar == LM_DFA_WORD) {
00106     lmconf = r->lm->config;
00107     if (!voca_load_wordlist_fp(fp, winfo, hmminfo, lmconf->wordrecog_head_silence_model_name, lmconf->wordrecog_tail_silence_model_name, (lmconf->wordrecog_silence_context_name[0] == '\0') ? NULL : lmconf->wordrecog_silence_context_name)) {
00108       return FALSE;
00109     }
00110   } else {
00111     if (!voca_load_htkdict_fp(fp, winfo, hmminfo, FALSE)) {
00112       dfa_info_free(dfa);
00113       return FALSE;
00114     }
00115   }
00116   *ret_dfa = dfa;
00117   *ret_winfo = winfo;
00118   return TRUE;
00119 }
00120 
00121 
00122 static void
00123 send_process_stat(RecogProcess *r)
00124 {
00125   module_send(module_sd, "<SR ID=\"%d\" NAME=\"%s\"", r->config->id, r->config->name);
00126   switch(r->lmtype) {
00127   case LM_PROB: module_send(module_sd, " LMTYPE=\"PROB\""); break;
00128   case LM_DFA: module_send(module_sd, " LMTYPE=\"DFA\""); break;
00129   }
00130   switch(r->lmvar) {
00131   case LM_NGRAM: module_send(module_sd, " LMVAR=\"NGRAM\""); break;
00132   case LM_DFA_GRAMMAR: module_send(module_sd, " LMVAR=\"GRAMMAR\""); break;
00133   case LM_DFA_WORD: module_send(module_sd, " LMVAR=\"WORD\""); break;
00134   case LM_NGRAM_USER: module_send(module_sd, " LMVAR=\"USER\""); break;
00135   }
00136   if (r->live) {
00137     module_send(module_sd, " LIVE=\"ACTIVE\"");
00138   } else {
00139     module_send(module_sd, " LIVE=\"INACTIVE\"");
00140   }
00141   module_send(module_sd, "/>\n.\n");
00142 }
00143 
00144 static void
00145 send_current_process(RecogProcess *r)
00146 {
00147   module_send(module_sd, "<RECOGPROCESS INFO=\"CURRENT\">\n");
00148   send_process_stat(r);
00149   module_send(module_sd, "</RECOGPROCESS>\n.\n");
00150 }
00151 
00179 static void
00180 msock_exec_command(char *command, Recog *recog)
00181 {
00182   DFA_INFO *new_dfa;
00183   WORD_INFO *new_winfo;
00184   static char *p, *q;
00185   int gid;
00186   int ret;
00187   RecogProcess *r;
00188 
00189   /* prompt the received command string */
00190   printf("[[%s]]\n",command);
00191 
00192   if (cur == NULL) {
00193     cur = recog->process_list;
00194   }
00195 
00196   if (strmatch(command, "STATUS")) {
00197     /* return status */
00198     if (recog->process_active) {
00199       module_send(module_sd, "<SYSINFO PROCESS=\"ACTIVE\"/>\n.\n");
00200     } else {
00201       module_send(module_sd, "<SYSINFO PROCESS=\"SLEEP\"/>\n.\n");
00202     }
00203   } else if (strmatch(command, "DIE")) {
00204     /* disconnect */
00205     close_socket(module_sd);
00206     module_sd = -1;
00207 #if defined(_WIN32) && !defined(__CYGWIN32__)
00208     /* this is single process and has not forked, so
00209        we just disconnect the connection here.  */
00210 #else
00211     /* this is a forked process, so exit here. */
00212 
00213 #endif
00214   } else if (strmatch(command, "VERSION")) {
00215     /* return version */
00216     module_send(module_sd, "<ENGINEINFO TYPE=\"%s\" VERSION=\"%s\" CONF=\"%s\"/>\n.\n",
00217                 JULIUS_PRODUCTNAME, JULIUS_VERSION, JULIUS_SETUP);
00218   } else if (strmatch(command, "PAUSE")) {
00219     /* pause recognition: will stop when the current input ends */
00220     j_request_pause(recog);
00221   } else if (strmatch(command, "TERMINATE")) {
00222     j_request_terminate(recog);
00223   } else if (strmatch(command, "RESUME")) {
00224     j_request_resume(recog);
00225   } else if (strmatch(command, "INPUTONCHANGE")) {
00226     /* change grammar switching timing policy */
00227     if (
00228         myfgets(buf, MAXBUFLEN, module_fp)
00229         == NULL) {
00230       fprintf(stderr, "Error: msock(INPUTONCHANGE): no argument\n");
00231       return;
00232     }
00233     if (strmatch(buf, "TERMINATE")) {
00234       recog->gram_switch_input_method = SM_TERMINATE;
00235     } else if (strmatch(buf, "PAUSE")) {
00236       recog->gram_switch_input_method = SM_PAUSE;
00237     } else if (strmatch(buf, "WAIT")) {
00238       recog->gram_switch_input_method = SM_WAIT;
00239     } else {
00240       fprintf(stderr, "Error: msock(INPUTONCHANGE): unknown method [%s]\n", buf); exit(-1);
00241     }
00242   } else if (strnmatch(command, "GRAMINFO", strlen("GRAMINFO"))) {
00243     send_gram_info(cur);
00244   } else if (strnmatch(command, "CHANGEGRAM", strlen("CHANGEGRAM"))) {
00245     /* receive grammar (DFA + DICT) from the socket, and swap the whole grammar  */
00246     /* read grammar name if any */
00247     p = &(command[strlen("CHANGEGRAM")]);
00248     while (*p == ' ' && *p != '\r' && *p != '\n' && *p != '\0') p++;
00249     if (*p != '\r' && *p != '\n' && *p != '\0') {
00250       q = buf;
00251       while (*p != ' ' && *p != '\r' && *p != '\n' && *p != '\0') *q++ = *p++;
00252       *q = '\0';
00253       p = buf;
00254     } else {
00255       p = NULL;
00256     }
00257     /* read a new grammar via socket */
00258     if (read_grammar(module_fp, &new_dfa, &new_winfo, cur->am->hmminfo, cur) == FALSE) {
00259       module_send(module_sd, "<GRAMMAR STATUS=\"ERROR\" REASON=\"WRONG DATA\"/>\n.\n");
00260     } else {
00261       if (cur->lmtype == LM_DFA) {
00262         /* delete all existing grammars */
00263         multigram_delete_all(cur->lm);
00264         /* register the new grammar to multi-gram tree */
00265         multigram_add(new_dfa, new_winfo, p, cur->lm);
00266         /* need to rebuild the global lexicon */
00267         /* tell engine to update at requested timing */
00268         schedule_grammar_update(recog);
00269         /* make sure this process will be activated */
00270         cur->active = 1;
00271         /* tell module client  */
00272         module_send(module_sd, "<GRAMMAR STATUS=\"RECEIVED\"/>\n.\n");
00273         send_gram_info(cur);
00274       } else {
00275         module_send(module_sd, "<GRAMMAR STATUS=\"ERROR\" REASON=\"NOT A GRAMMAR-BASED LM\"/>\n.\n");
00276       }
00277     }
00278   } else if (strnmatch(command, "ADDGRAM", strlen("ADDGRAM"))) {
00279     /* receive grammar and add it to the current grammars */
00280     /* read grammar name if any */
00281     p = &(command[strlen("ADDGRAM")]);
00282     while (*p == ' ' && *p != '\r' && *p != '\n' && *p != '\0') p++;
00283     if (*p != '\r' && *p != '\n' && *p != '\0') {
00284       q = buf;
00285       while (*p != ' ' && *p != '\r' && *p != '\n' && *p != '\0') *q++ = *p++;
00286       *q = '\0';
00287       p = buf;
00288     } else {
00289       p = NULL;
00290     }
00291     /* read a new grammar via socket */
00292     if (read_grammar(module_fp, &new_dfa, &new_winfo, cur->am->hmminfo, cur) == FALSE) {
00293       module_send(module_sd, "<GRAMMAR STATUS=\"ERROR\" REASON=\"WRONG DATA\"/>\n.\n");
00294     } else {
00295       if (cur->lmtype == LM_DFA) {
00296         /* add it to multi-gram tree */
00297         multigram_add(new_dfa, new_winfo, p, cur->lm);
00298         /* need to rebuild the global lexicon */
00299         /* make sure this process will be activated */
00300         cur->active = 1;
00301         /* tell engine to update at requested timing */
00302         schedule_grammar_update(recog);
00303         /* tell module client  */
00304         module_send(module_sd, "<GRAMMAR STATUS=\"RECEIVED\"/>\n.\n");
00305         send_gram_info(cur);
00306       } else {
00307         module_send(module_sd, "<GRAMMAR STATUS=\"ERROR\" REASON=\"NOT A GRAMMAR-BASED LM\"/>\n.\n");
00308       }
00309     }
00310   } else if (strmatch(command, "DELGRAM")) {
00311     /* remove the grammar specified by ID or name */
00312     /* read a list of grammar IDs to be deleted */
00313     if (
00314         myfgets(buf, MAXBUFLEN, module_fp)
00315         == NULL) {
00316       fprintf(stderr, "Error: msock(DELGRAM): no argument\n");
00317       return;
00318     }
00319     /* extract IDs and mark them as delete
00320        (actual deletion will be performed on the next 
00321     */
00322     if (cur->lmtype == LM_DFA) {
00323       for(p=strtok(buf," ");p;p=strtok(NULL," ")) {
00324         q = p;
00325         while(*q != '\0' && *q != '\r' && *q != '\n') {
00326           if (*q < '0' || *q > '9') break;
00327           q++;
00328         }
00329         if (*q == '\0' || *q == '\r' || *q == '\n') { /* numeric */
00330           gid = atoi(p);
00331         } else {                /* string */
00332           gid = multigram_get_id_by_name(cur->lm, p);
00333           if (gid == -1) continue;
00334         }
00335         if (multigram_delete(gid, cur->lm) == FALSE) { /* deletion marking failed */
00336           fprintf(stderr, "Warning: msock(DELGRAM): gram #%d failed to delete, ignored\n", gid);
00337           /* tell module */
00338           module_send(module_sd, "<GRAMMAR STATUS=\"ERROR\" REASON=\"Gram #%d not found\"/>\n.\n", gid);
00339         }
00340       }
00341       /* need to rebuild the global lexicon */
00342       /* tell engine to update at requested timing */
00343       schedule_grammar_update(recog);
00344     } else {
00345       module_send(module_sd, "<GRAMMAR STATUS=\"ERROR\" REASON=\"NOT A GRAMMAR-BASED LM\"/>\n.\n");
00346     }
00347   } else if (strmatch(command, "ACTIVATEGRAM")) {
00348     /* activate grammar in this engine */
00349     /* read a list of grammar IDs or names to be activated */
00350     if (
00351         myfgets(buf, MAXBUFLEN, module_fp)
00352         == NULL) {
00353       fprintf(stderr, "Error: msock(ACTIVATEGRAM): no argument\n");
00354       return;
00355     }
00356     /* mark them as active */
00357     if (cur->lmtype == LM_DFA) {
00358       for(p=strtok(buf," ");p;p=strtok(NULL," ")) {
00359         q = p;
00360         while(*q != '\0' && *q != '\r' && *q != '\n') {
00361           if (*q < '0' || *q > '9') break;
00362           q++;
00363         }
00364         if (*q == '\0' || *q == '\r' || *q == '\n') { /* numeric */
00365           gid = atoi(p);
00366         } else {                /* string */
00367           gid = multigram_get_id_by_name(cur->lm, p);
00368           if (gid == -1) continue;
00369         }
00370         ret = multigram_activate(gid, cur->lm);
00371         if (ret == 1) {
00372           /* already active */
00373           module_send(module_sd, "<WARN MESSAGE=\"Gram #%d already active\"/>\n.\n", gid);
00374         } else if (ret == -1) {
00375           /* not found */
00376           module_send(module_sd, "<WARN MESSAGE=\"Gram #%d not found\"/>\n.\n", gid);
00377         }       /* else success */
00378       }
00379       /* tell engine to update at requested timing */
00380       schedule_grammar_update(recog);
00381     } else {
00382       module_send(module_sd, "<GRAMMAR STATUS=\"ERROR\" REASON=\"NOT A GRAMMAR-BASED LM\"/>\n.\n");
00383     }
00384   } else if (strmatch(command, "DEACTIVATEGRAM")) {
00385     /* deactivate grammar in this engine */
00386     /* read a list of grammar IDs or names to be de-activated */
00387     if (
00388         myfgets(buf, MAXBUFLEN, module_fp)
00389         == NULL) {
00390       fprintf(stderr, "Error: msock(DEACTIVATEGRAM): no argument\n");
00391       return;
00392     }
00393     if (cur->lmtype == LM_DFA) {
00394       /* mark them as not active */
00395       for(p=strtok(buf," ");p;p=strtok(NULL," ")) {
00396         q = p;
00397         while(*q != '\0' && *q != '\r' && *q != '\n') {
00398           if (*q < '0' || *q > '9') break;
00399           q++;
00400         }
00401         if (*q == '\0' || *q == '\r' || *q == '\n') { /* numeric */
00402           gid = atoi(p);
00403         } else {                /* string */
00404           gid = multigram_get_id_by_name(cur->lm, p);
00405           if (gid == -1) continue;
00406         }
00407         ret = multigram_deactivate(gid, cur->lm);
00408         if (ret == 1) {
00409           /* already inactive */
00410           module_send(module_sd, "<WARN MESSAGE=\"Gram #%d already inactive\"/>\n.\n", gid);
00411         } else if (ret == -1) {
00412           /* not found */
00413           module_send(module_sd, "<WARN MESSAGE=\"Gram #%d not found\"/>\n.\n", gid);
00414         }       /* else success */
00415       }
00416       schedule_grammar_update(recog);
00417     } else {
00418       module_send(module_sd, "<GRAMMAR STATUS=\"ERROR\" REASON=\"NOT A GRAMMAR-BASED LM\"/>\n.\n");
00419     }
00420   } else if (strmatch(command, "SYNCGRAM")) {
00421     /* update grammar if necessary */
00422     if (cur->lmtype == LM_DFA) {
00423       multigram_update(cur->lm);  /* some modification occured if return TRUE */
00424       for(r=recog->process_list;r;r=r->next) {
00425         if (r->lmtype == LM_DFA && r->lm->global_modified) {
00426           multigram_build(r);
00427         }
00428       }
00429       cur->lm->global_modified = FALSE;
00430       module_send(module_sd, "<GRAMMAR STATUS=\"READY\"/>\n.\n");
00431     } else {
00432       module_send(module_sd, "<GRAMMAR STATUS=\"ERROR\" REASON=\"NOT A GRAMMAR-BASED LM\"/>\n.\n");
00433     }
00434   } else if (strmatch(command, "CURRENTPROCESS")) {
00435     JCONF_SEARCH *sconf;
00436     RecogProcess *r;
00437     if (
00438         myfgets(buf, MAXBUFLEN, module_fp)
00439         == NULL) {
00440       /* when no argument, just return current process */
00441       send_current_process(cur);
00442       return;
00443     }
00444     if (buf[0] == '\0') {
00445       /* when no argument, just return current process */
00446       send_current_process(cur);
00447       return;
00448     }
00449     sconf = j_get_searchconf_by_name(recog->jconf, buf);
00450     if (sconf == NULL) {
00451       fprintf(stderr, "Error: msock(CURRENTPROCESS): no such process \"%s\"\n", buf);
00452       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"NO SUCH PROCESS\"/>\n.\n");
00453       return;
00454     }
00455     for(r=recog->process_list;r;r=r->next) {
00456       if (r->config == sconf) {
00457         cur = r;
00458         break;
00459       }
00460     }
00461     if (!r) {
00462       fprintf(stderr, "Error: msock(CURRENTPROCESS): no process assigned to searchconf \"%s\"??\n", buf);
00463       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"NO SUCH PROCESS\"/>\n.\n");
00464       return;
00465     }
00466     send_current_process(cur);
00467   }
00468 
00469   else if (strmatch(command, "SHIFTPROCESS")) {
00470     cur = cur->next;
00471     if (cur == NULL) {
00472       fprintf(stderr, "SHIFTPROCESS: reached end, rotated to first\n");
00473       cur = recog->process_list;
00474     }
00475     send_process_stat(cur);
00476   }
00477 
00478   else if (strmatch(command, "ADDPROCESS")) {
00479     Jconf *jconf;
00480     JCONF_LM *lmconf;
00481     JCONF_AM *amconf;
00482     JCONF_SEARCH *sconf;
00483     RecogProcess *r;
00484 
00485     if (
00486         myfgets(buf, MAXBUFLEN, module_fp)
00487         == NULL) {
00488       fprintf(stderr, "Error: msock(ADDPROCESS): no argument\n");
00489       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"NO ARGUMENT\"/>\n.\n");
00490       return;
00491     }
00492     /* load specified jconf file and use its last LM conf as new */
00493     jconf = j_jconf_new();
00494     j_config_load_file(jconf, buf);
00495     lmconf = jconf->lmnow;
00496 
00497     /* create a search instance */
00498     sconf = j_jconf_search_new();
00499     /* all the parameters are defaults */
00500 
00501     /* create process instance with new LM and SR */
00502     if (j_process_add_lm(recog, lmconf, sconf, buf) == FALSE) {
00503       fprintf(stderr, "Error: failed to regist new process \"%s\"\n", buf);
00504       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"FAILED TO REGISTER\"/>\n.\n");
00505       j_jconf_search_free(sconf);
00506       return;
00507     }
00508     printf("added process: SR%02d %s\n", sconf->id, sconf->name);
00509     module_send(module_sd, "<RECOGPROCESS INFO=\"ADDED\">\n");
00510     for(r=recog->process_list;r;r=r->next) {
00511       if (r->config == sconf) {
00512         send_process_stat(r);
00513       }
00514     }
00515     module_send(module_sd, "</RECOGPROCESS>\n.\n");
00516   }
00517 
00518   else if (strmatch(command, "DELPROCESS")) {
00519     JCONF_SEARCH *sconf;
00520     JCONF_LM *lmconf;
00521     RecogProcess *r;
00522 
00523     if (
00524         myfgets(buf, MAXBUFLEN, module_fp)
00525         == NULL) {
00526       fprintf(stderr, "Error: msock(DELPROCESS): no argument\n");
00527       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"NO ARGUMENT\"/>\n.\n");
00528       return;
00529     }
00530 
00531     sconf =  j_get_searchconf_by_name(recog->jconf, buf);
00532     if (sconf == NULL) {
00533       fprintf(stderr, "Error: msock(DELPROCESS): no searchconf named %s\n", buf);
00534       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"NO RECOGPROCESS OF THE NAME\"/>\n.\n");
00535       return;
00536     }
00537 
00538     lmconf = sconf->lmconf;
00539     printf("remove process: SR%02d %s, LM%02d %s\n", sconf->id, sconf->name, lmconf->id, lmconf->name);
00540     module_send(module_sd, "<RECOGPROCESS INFO=\"DELETE\">\n");
00541     for(r=recog->process_list;r;r=r->next) {
00542       if (r->config == sconf) send_process_stat(r);
00543     }
00544     module_send(module_sd, "</RECOGPROCESS>\n.\n");
00545     j_process_remove(recog, sconf);
00546     j_process_lm_remove(recog, lmconf);
00547     /* change current */
00548     for(r=recog->process_list;r;r=r->next) {
00549       if (r == cur) break;
00550     }
00551     if (!r) {
00552       cur = recog->process_list;
00553       printf("now current moved to SR%02d %s\n", cur->config->id, cur->config->name);
00554       send_current_process(cur);
00555     }
00556     
00557   }
00558 
00559   else if (strmatch(command, "LISTPROCESS")) {
00560     RecogProcess *r;
00561     
00562     module_send(module_sd, "<RECOGPROCESS INFO=\"STATUS\">\n");
00563     for(r=recog->process_list;r;r=r->next) {
00564       send_process_stat(r);
00565     }
00566     module_send(module_sd, "</RECOGPROCESS>\n.\n");
00567   }
00568 
00569   else if (strmatch(command, "ACTIVATEPROCESS")) {
00570     if (
00571         myfgets(buf, MAXBUFLEN, module_fp)
00572         == NULL) {
00573       fprintf(stderr, "Error: msock(ACTIVATEPROCESS): no argument\n");
00574       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"NO ARGUMENT\"/>\n.\n");
00575       return;
00576     }
00577     if (j_process_activate(recog, buf) == FALSE) {
00578       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"ACTIVATION FAILED\"/>\n.\n");
00579     } else {
00580       module_send(module_sd, "<RECOGPROCESS INFO=\"ACTIVATED\" NAME=\"%s\"/>\n.\n", buf);
00581     }
00582   }
00583   else if (strmatch(command, "DEACTIVATEPROCESS")) {
00584     if (
00585         myfgets(buf, MAXBUFLEN, module_fp)
00586         == NULL) {
00587       fprintf(stderr, "Error: msock(DEACTIVATEPROCESS): no argument\n");
00588       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"NO ARGUMENT\"/>\n.\n");
00589       return;
00590     }
00591     if (j_process_deactivate(recog, buf) == FALSE) {
00592       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"DEACTIVATION FAILED\"/>\n.\n");
00593     } else {
00594       module_send(module_sd, "<RECOGPROCESS INFO=\"DEACTIVATED\" NAME=\"%s\"/>\n.\n", buf);
00595     }
00596     module_send(module_sd, ".\n");
00597   }
00598   else if (strmatch(command, "ADDWORD")) {
00599     WORD_INFO *words;
00600     boolean ret;
00601     int id;
00602 
00603     /* get gramamr ID to add */
00604     if (
00605         myfgets(buf, MAXBUFLEN, module_fp)
00606         == NULL) {
00607       fprintf(stderr, "Error: msock(DEACTIVATEPROCESS): no argument\n");
00608       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"NO ARGUMENT\"/>\n.\n");
00609       return;
00610     }
00611     id = atoi(buf);
00612 
00613     /* read list of word entries, will stop by "DICEND" */
00614     words = word_info_new();
00615     voca_load_start(words, cur->am->hmminfo, FALSE);
00616     while (
00617         myfgets(buf, MAXBUFLEN, module_fp)
00618         != NULL) {
00619       if (cur->lmvar == LM_DFA_WORD) {
00620         ret = voca_load_word_line(buf, words, cur->am->hmminfo, 
00621                                   cur->lm->config->wordrecog_head_silence_model_name,
00622                                   cur->lm->config->wordrecog_tail_silence_model_name,
00623                                   (cur->lm->config->wordrecog_silence_context_name[0] == '\0') ? NULL : cur->lm->config->wordrecog_silence_context_name);
00624       } else {
00625         ret = voca_load_line(buf, words, cur->am->hmminfo);
00626       }
00627       if (ret == FALSE) break;
00628     }
00629     ret = voca_load_end(words);
00630     if (ret == FALSE) {
00631       fprintf(stderr, "Error: msock(ADDWORD): error in reading word entries\n");
00632       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"ERROR IN READING WORD ENTRIES\"/>\n.\n");
00633       word_info_free(words);
00634       return;
00635     }
00636     if (words->num == 0) {
00637       fprintf(stderr, "Error: msock(ADDWORD): no word specified\n");
00638       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"NO WORD SPECIFIED\"/>\n.\n");
00639       word_info_free(words);
00640       return;
00641     }
00642     printf("%d words read\n", words->num);
00643     /* add the words to the grammar */
00644     if (multigram_add_words_to_grammar_by_id(cur->lm, id, words) == FALSE) {
00645       fprintf(stderr, "Error: msock(ADDWORD): failed to add words to grammar #%d\n", id);
00646       module_send(module_sd, "<RECOGPROCESS STATUS=\"ERROR\" REASON=\"FAILED\"/>\n.\n");
00647       word_info_free(words);
00648       return;
00649     }
00650     /* book for update */
00651     schedule_grammar_update(recog);
00652     module_send(module_sd, "%d words added to grammar #%d\n.\n", words->num, id);
00653     module_send(module_sd, "<RECOGPROCESS INFO=\"ADDEDWORD\" GRAMMARID=\"%d\" NUM=\"%d\"/>\n.\n", id, words->num);
00654 
00655     word_info_free(words);
00656   }
00657 }
00658 
00671 static void
00672 msock_check_and_process_command(Recog *recog, void *dummy)
00673 {
00674   fd_set rfds;
00675   int ret;
00676   struct timeval tv;
00677 
00678   /* check if some commands are waiting in queue */
00679   FD_ZERO(&rfds);
00680   FD_SET(module_sd, &rfds);
00681   tv.tv_sec = 0;
00682   tv.tv_usec = 0;             /* 0 msec timeout: return immediately */
00683   ret = select(module_sd+1, &rfds, NULL, NULL, &tv);
00684   if (ret < 0) {
00685     perror("msock_check_and_process_command: cannot poll\n");
00686   }
00687   if (ret > 0) {
00688     /* there is data to read */
00689     /* process command and change status if necessaty */
00690     while(select(module_sd+1, &rfds, NULL, NULL, &tv) > 0 &&
00691           myfgets(mbuf, MAXBUFLEN, module_fp)
00692           != NULL) {
00693       msock_exec_command(mbuf, recog);
00694     }
00695   }
00696 }
00697 
00713 static void
00714 msock_process_command(Recog *recog, void *dummy)
00715 {
00716 
00717   while(!recog->process_active) {
00718     if (
00719         myfgets(mbuf, MAXBUFLEN, module_fp)
00720         != NULL) {
00721       msock_exec_command(mbuf, recog);
00722     }
00723   }
00724 }
00725 
00726 static void
00727 module_regist_callback(Recog *recog, void *data)
00728 {
00729   callback_add(recog, CALLBACK_POLL, msock_check_and_process_command, data);
00730   callback_add(recog, CALLBACK_PAUSE_FUNCTION, msock_process_command, data);
00731 }
00732 
00733 /************************************************************************/
00734 static boolean
00735 opt_module(Jconf *jconf, char *arg[], int argnum)
00736 {
00737   module_mode = TRUE;
00738   if (argnum > 0) {
00739     module_port = atoi(arg[0]);
00740   }
00741   return TRUE;
00742 }
00743 
00744 static boolean
00745 opt_outcode(Jconf *jconf, char *arg[], int argnum)
00746 {
00747   decode_output_selection(arg[0]);
00748   return TRUE;
00749 }
00750 
00751 void
00752 module_add_option()
00753 {
00754   j_add_option("-module", 1, 0, "run as a server module", opt_module);
00755   j_add_option("-outcode", 1, 1, "select info to output to the module: WLPSCwlps", opt_outcode);
00756 }
00757 
00758 boolean
00759 is_module_mode()
00760 {
00761   return module_mode;
00762 }
00763 
00764 void
00765 module_setup(Recog *recog, void *data)
00766 {
00767   /* register result output callback functions */
00768   module_regist_callback(recog, data);
00769   setup_output_msock(recog, data);
00770 }
00771   
00772 void
00773 module_server()
00774 {
00775   int listen_sd;        
00776 #if defined(_WIN32) && !defined(__CYGWIN32__)
00777   int sd;
00778 #endif
00779   
00780   /* prepare socket to listen */
00781   if ((listen_sd = ready_as_server(module_port)) < 0) {
00782     fprintf(stderr, "Error: failed to bind socket\n");
00783     return;
00784   }
00785   
00786   printf  ("///////////////////////////////\n");
00787   printf  ("///  Module mode ready\n");
00788   printf  ("///  waiting client at %5d\n", module_port);
00789   printf  ("///////////////////////////////\n");
00790   printf  ("///  ");
00791   
00792   /* no fork, just wait for one connection and proceed */
00793   if ((module_sd = accept_from(listen_sd)) < 0) {
00794     fprintf(stderr, "Error: failed to accept connection\n");
00795     return;
00796   }
00797 #if defined(_WIN32) && !defined(__CYGWIN32__)
00798   /* call winsock function to make the socket capable of reading/writing */
00799   if ((sd = _open_osfhandle(module_sd, O_RDWR|O_BINARY)) < 0) {
00800     fprintf(stderr, "Error: failed to open_osfhandle\n");
00801     return;
00802   }
00803   if ((module_fp = fdopen(sd, "rb+")) == NULL) {
00804     fprintf(stderr, "Error: failed to fdopen socket\n");
00805     return;
00806   }
00807 #else
00808   if ((module_fp = fdopen(module_sd, "r+")) == NULL) {
00809     fprintf(stderr, "Error; failed to fdopen socket\n");
00810     return;
00811   }
00812 #endif
00813 }
00814 
00815 void
00816 module_disconnect()
00817 {
00818   /* disconnect control module */
00819   if (module_sd >= 0) { /* connected now */
00820     module_send(module_sd, "<SYSINFO PROCESS=\"ERREXIT\"/>\n.\n");
00821     close_socket(module_sd);
00822     module_sd = -1;
00823   }
00824 }