/* * (c) 1998-2005 Jirka Hanika * * This single source file src/say-epos.cc, but NOT THE REST OF THIS PACKAGE, * is considered to be in Public Domain. Parts of this single source file may be * freely incorporated into any commercial or other software. * * Most files in this package are strictly covered by the General Public * License version 2, to be found in doc/COPYING. Should GPL and the paragraph * above come into any sort of legal conflict, GPL takes precedence. * * This file implements a simple TTSCP client. See doc/english/ttscp.sgml * for a preliminary technical specification. * * This file is almost a plain C source file. We compile it with a C++ * compiler just to avoid additional configure complexity. */ #define THIS_IS_A_TTSCP_CLIENT #include "common.h" #ifdef HAVE_WINSVC_H bool start_service(); bool stop_service(); #else bool start_service() { return true; } bool stop_service() { return true; } #endif #ifndef HAVE_TERMINATE void terminate(void) { abort(); } #endif const char *COMMENT_LINES = "#;\r\n"; const char *WHITESPACE = " \t\r"; const char *output_file = NULL; const char *charset = "8859-2"; bool chunking = false; bool show_segments = false; bool debug_ttscp = false; bool wavfile = false; bool wavstdout = false; bool traditional = true; bool do_say = true; const char *other_traffic_prefix = "Unexpected: "; #define STDIN_BUFF_SIZE 550000 int ctrld, datad; /* file descriptors for the control and data connections */ char *data = NULL; char *ch; char *dh; void shriek(char *txt) { fprintf(stderr, "Client side error: %s\n", txt); exit(1); } void shriek(int, char *txt) { shriek(txt); } // #include "exc.h" #include "client.cc" int send_to_epos(const char *buffer, int socket) { if (debug_ttscp && socket == ctrld) printf("%s", buffer); return sputs(buffer, socket); } int get_result(int sd) { while (sgets(scratch, scfg->scratch_size, sd)) { scratch[scfg->scratch_size] = 0; if (debug_ttscp && sd == ctrld) printf("Received: %s\n", scratch); switch(*scratch) { case '1': continue; case '2': return 2; case '3': break; case '4': printf("%s\n", scratch+strspn(scratch, "0123456789x ")); return 4; case '6': if (!strncmp(scratch, "600 ", 4)) { exit(0); } /* else fall through */ case '8': printf("%s\n", scratch+strspn(scratch, "0123456789x ")); exit(2); case '5': case '7': case '9': case '0': printf("%s\n", scratch); shriek("Unhandled response code"); default : ; } char *o = scratch+strspn(scratch, "0123456789 -"); if (*scratch && *o) printf("%s%s\n", other_traffic_prefix, o); } return 8; /* guessing */ } int size; char *get_data() { char *b = NULL; size = 0; while (sgets(scratch, scfg->scratch_size, ctrld)) { scratch[scfg->scratch_size] = 0; if (debug_ttscp) printf("Received: %s\n", scratch); if (strchr("2468", *scratch)) { /* all done, write result */ if (*scratch != '2') shriek(scratch); if (!size) shriek("No processed data received"); b[size] = 0; return b; } if (!strncmp(scratch, "123 ", 4)) { int count; sgets(scratch, scfg->scratch_size, ctrld); scratch[scfg->scratch_size] = 0; sscanf(scratch, "%d", &count); b = size ? (char *)realloc(b, size + count + 1) : (char *)malloc(count + 1); int limit = size + count; while (size < limit) size += yread(datad, b + size, limit - size); } } if (size) shriek("Disconnect during transmit"); else shriek("Disconnect before transmit"); return NULL; } void say_data() { if (!data) data = strdup("No."); send_to_epos("strm $", ctrld); send_to_epos(dh, ctrld); if (chunking) send_to_epos(":chunk", ctrld); if (traditional) send_to_epos(":raw:rules:diphs:synth:", ctrld); else send_to_epos(":raw:rules:dump:syn:", ctrld); if (wavfile || wavstdout) send_to_epos("$", ctrld), send_to_epos(dh, ctrld); else send_to_epos("#localsound", ctrld); send_to_epos("\r\n", ctrld); send_to_epos("appl ", ctrld); sprintf(scratch, "%d", (int)strlen(data)); send_to_epos(scratch, ctrld); send_to_epos("\r\n", ctrld); send_to_epos(data, datad); if (get_result(ctrld) > 2) shriek("Could not set up a stream"); char *b; if (wavfile || wavstdout) { b = get_data(); FILE *f = wavstdout ? stdout : fopen(output_file, "wb"); if (!size || !b) shriek("Could not get waveform"); if (!f || !fwrite(b, size, 1, f)) shriek("Could not write waveform"); if (!wavstdout) fclose(f); free(b); return; } if (get_result(ctrld) > 2) shriek("Could not apply a stream"); } void trans_data() { if (!data) data = strdup("No."); send_to_epos("strm $", ctrld); send_to_epos(dh, ctrld); if (chunking) send_to_epos(":chunk", ctrld); if (show_segments) send_to_epos(traditional ? ":raw:rules:diphs:$" : ":raw:rules:dump:$", ctrld); else send_to_epos(":raw:rules:print:$", ctrld); send_to_epos(dh, ctrld); send_to_epos("\r\n", ctrld); send_to_epos("appl ", ctrld); sprintf(scratch, "%d", (int)strlen(data)); send_to_epos(scratch, ctrld); send_to_epos("\r\n", ctrld); send_to_epos(data, datad); get_result(ctrld); if (show_segments) { segment *b = (segment *)get_data(); if (traditional) for (int i=1; idebug) scfg->debug=true; // else if (scfg->warnings) // scfg->always_dbg--; break; default : shriek("Unknown short option"); } if (j==ar+1) { //dash only goto join; } break; case 0: join: if (data) { int needed = strlen(data) + strlen(ar) + 2; if (needed > scfg->scratch_size) { scratch = (char *)realloc(scratch, needed + 2); scfg->scratch_size = needed; } sprintf(scratch, "%s %s", data, ar); free(data); data = strdup(scratch); } else data = strdup(ar); break; default: shriek("Too many dashes "); } } if (data && !strcmp("-", data)) { free(data); data = (char *)malloc(STDIN_BUFF_SIZE + 2); data[fread(data, 1, STDIN_BUFF_SIZE, stdin)] = 0; } if (data) for(char *p=data; *p; p++) if (*p == '\n' || *p == '\r') *p=' '; if (data && strspn(data, ",.!?:;+=-*/&^%#$_<>{}()[]|\\~`' \04\t\"") == strlen(data)) shriek("Input text too funny"); } /* * main() implements what most TTSCP clients do: it opens two TTSCP connections, * converts one of them to a data connection dependent on the other one. * Then, commands in a file found using the TTSCP_USER environment variable * are transmitted and synthesis and transcription procedures invoked. * Last, general cleanup is done (the connections are gracefully closed.) * * Note that the connection establishment code is less intuitive than * it could be because of paralelism oriented code ordering. */ int main(int argc, char **argv) { if (argc > 1 && !strcmp(argv[1], "--help")) { dump_help(); exit(0); } #ifdef HAVE_WINSOCK if (WSAStartup(MAKEWORD(2,0), (LPWSADATA)scratch)) shriek(464, "No winsock"); charset = "cp1250"; #endif start_service(); /* Windows NT etc. only */ ctrld = connect_socket(0, 0); datad = connect_socket(0, 0); send_to_epos("data ", datad); ch = get_handle(ctrld); send_to_epos(ch, datad); send_to_epos("\r\n", datad); free(ch); send_to_epos("setl charset ",ctrld); send_to_epos(charset, ctrld); send_to_epos("\r\n", ctrld); get_result(ctrld); send_cmd_line(argc, argv); dh = get_handle(datad); get_result(datad); // #ifdef HAVE_GETENV FILE *f = NULL; char *ttscp_user_config = getenv("TTSCP_USER"); if (ttscp_user_config) f = fopen(ttscp_user_config, "rt"); if (f) { while (!feof(f)) { *scratch = 0; fgets(scratch, scfg->scratch_size, f); if (*scratch && !strchr(COMMENT_LINES, scratch[strspn(scratch, WHITESPACE)])) { send_to_epos(scratch, ctrld); get_result(ctrld); } } fclose(f); } /// #endif if (!wavstdout) trans_data(); if (do_say) say_data(); send_to_epos("delh ", ctrld); send_to_epos(dh, ctrld); send_to_epos("\r\ndone\r\n", ctrld); get_result(ctrld); get_result(ctrld); close(datad); close(ctrld); return 0; }