SVN_SILENT made messages (.desktop file)
[kdeaccessibility.git] / kmouth / speech.cpp
blob2388df7b341eef691c9b9c2981de4f336fb4e6ad
1 /***************************************************************************
2 speech.cpp - description
3 -------------------
4 begin : Son Sep 8 2002
5 copyright : (C) 2002 by Gunnar Schmi Dt
6 email : kmouth@schmi-dt.de
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include "speech.h"
20 #include <QStack>
21 #include <QRegExp>
22 #include <QTextCodec>
23 #include <QFile>
24 #include <QHash>
25 //Added by qt3to4:
26 #include <QTextStream>
27 #include <kdebug.h>
29 #include <kdeversion.h>
30 #define macroExpander
31 #include <kmacroexpander.h>
33 Speech::Speech() {
36 Speech::~Speech() {
39 QString Speech::prepareCommand (QString command, const QString &text,
40 const QString &filename, const QString &language) {
41 #ifdef macroExpander
42 QHash<QChar,QString> map;
43 map['t'] = text;
44 map['f'] = filename;
45 map['l'] = language;
46 return KMacroExpander::expandMacrosShellQuote (command, map);
47 #else
48 QStack<bool> stack; // saved isdoublequote values during parsing of braces
49 bool issinglequote=false; // inside '...' ?
50 bool isdoublequote=false; // inside "..." ?
51 int noreplace=0; // nested braces when within ${...}
52 QString escText = K3ShellProcess::quote(text);
54 // character sequences that change the state or need to be otherwise processed
55 QRegExp re_singlequote("('|%%|%t|%f|%l)");
56 QRegExp re_doublequote("(\"|\\\\|`|\\$\\(|\\$\\{|%%|%t|%f|%l)");
57 QRegExp re_noquote ("('|\"|\\\\|`|\\$\\(|\\$\\{|\\(|\\{|\\)|\\}|%%|%t|%f|%l)");
59 // parse the command:
60 for (int i = re_noquote.search(command);
61 i != -1;
62 i = (issinglequote?re_singlequote.search(command,i)
63 :isdoublequote?re_doublequote.search(command,i)
64 :re_noquote.search(command,i))
66 // while there are character sequences that need to be processed
68 if ((command[i]=='(') || (command[i]=='{')) { // (...) or {...}
69 // assert(isdoublequote == false)
70 stack.push(isdoublequote);
71 if (noreplace > 0)
72 // count nested braces when within ${...}
73 noreplace++;
74 i++;
76 else if (command[i]=='$') { // $(...) or ${...}
77 stack.push(isdoublequote);
78 isdoublequote = false;
79 if ((noreplace > 0) || (command[i+1]=='{'))
80 // count nested braces when within ${...}
81 noreplace++;
82 i+=2;
84 else if ((command[i]==')') || (command[i]=='}')) {
85 // $(...) or (...) or ${...} or {...}
86 if (!stack.isEmpty())
87 isdoublequote = stack.pop();
88 else
89 qWarning("Parse error.");
90 if (noreplace > 0)
91 // count nested braces when within ${...}
92 noreplace--;
93 i++;
95 else if (command[i]=='\'') {
96 issinglequote=!issinglequote;
97 i++;
99 else if (command[i]=='"') {
100 isdoublequote=!isdoublequote;
101 i++;
103 else if (command[i]=='\\')
104 i+=2;
105 else if (command[i]=='`') {
106 // Replace all `...` with safer $(...)
107 command.replace (i, 1, "$(");
108 QRegExp re_backticks("(`|\\\\`|\\\\\\\\|\\\\\\$)");
109 for (int i2=re_backticks.search(command,i+2);
110 i2!=-1;
111 i2=re_backticks.search(command,i2)
114 if (command[i2] == '`') {
115 command.replace (i2, 1, ")");
116 i2=command.length(); // leave loop
118 else {
119 // remove backslash and ignore following character
120 command.remove (i2, 1);
121 i2++;
124 // Leave i unchanged! We need to process "$("
126 else if (noreplace > 0) { // do not replace macros within ${...}
127 if (issinglequote)
128 i+=re_singlequote.matchedLength();
129 else if (isdoublequote)
130 i+=re_doublequote.matchedLength();
131 else
132 i+=re_noquote.matchedLength();
134 else { // replace macro
135 QString match, v;
137 // get match
138 if (issinglequote)
139 match=re_singlequote.cap();
140 else if (isdoublequote)
141 match=re_doublequote.cap();
142 else
143 match=re_noquote.cap();
145 // substitute %variables
146 if (match=="%t")
147 v = escText;
148 else if (match=="%f")
149 v = filename;
150 else if (match=="%%")
151 v = "%";
152 else if (match=="%l")
153 v = language;
155 // %variable inside of a quote?
156 if (isdoublequote)
157 v='"'+v+'"';
158 else if (issinglequote)
159 v='\''+v+'\'';
161 command.replace (i, match.length(), v);
162 i+=v.length();
165 return command;
166 #endif
169 void Speech::speak(QString command, bool stdIn, const QString &text, const QString &language, int encoding, QTextCodec *codec) {
170 if (text.length () > 0) {
171 // 1. prepare the text:
172 // 1.a) encode the text
173 QTextStream ts (encText, QIODevice::WriteOnly);
174 if (encoding == Local)
175 ts.setEncoding (QTextStream::Locale);
176 else if (encoding == Latin1)
177 ts.setEncoding (QTextStream::Latin1);
178 else if (encoding == Unicode)
179 ts.setEncoding (QTextStream::Unicode);
180 else
181 ts.setCodec (codec);
182 ts << text;
184 // 1.b) create a temporary file for the text
185 tempFile.open();
186 QTextStream fs ( &tempFile );
187 if (encoding == Local)
188 fs.setEncoding (QTextStream::Locale);
189 else if (encoding == Latin1)
190 fs.setEncoding (QTextStream::Latin1);
191 else if (encoding == Unicode)
192 fs.setEncoding (QTextStream::Unicode);
193 else
194 fs.setCodec (codec);
195 fs << text;
196 fs << endl;
197 QString filename = tempFile.fileName();
198 tempFile.flush();
200 // 2. prepare the command:
201 command = prepareCommand (command, encText, filename, language);
204 // 3. create a new process
205 process << command;
206 connect(&process, SIGNAL(processExited(K3Process *)), this, SLOT(processExited(K3Process *)));
207 connect(&process, SIGNAL(wroteStdin(K3Process *)), this, SLOT(wroteStdin(K3Process *)));
208 connect(&process, SIGNAL(receivedStdout(K3Process *, char *, int)), this, SLOT(receivedStdout(K3Process *, char *, int)));
209 connect(&process, SIGNAL(receivedStderr(K3Process *, char *, int)), this, SLOT(receivedStderr(K3Process *, char *, int)));
211 // 4. start the process
212 if (stdIn) {
213 process.start(K3Process::NotifyOnExit, K3Process::All);
214 if (encText.size() > 0)
215 process.writeStdin(encText, encText.size());
216 else
217 process.closeStdin();
219 else
220 process.start(K3Process::NotifyOnExit, K3Process::AllOutput);
224 void Speech::receivedStdout (K3Process *, char *buffer, int buflen) {
225 kDebug() << QString::fromLatin1(buffer, buflen) + '\n';
227 void Speech::receivedStderr (K3Process *, char *buffer, int buflen) {
228 kDebug() << QString::fromLatin1(buffer, buflen) + '\n';
231 void Speech::wroteStdin(K3Process *) {
232 process.closeStdin();
235 void Speech::processExited(K3Process *) {
236 delete this;
239 #include "speech.moc"