SVN_SILENT made messages (.desktop file)
[kdeaccessibility.git] / kmouth / speech.cpp
blob2ede1bd1ffccdebc08945e0762fe7b714a4de30a
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 <QStringList>
22 #include <QRegExp>
23 #include <QTextCodec>
24 #include <QFile>
25 #include <QHash>
26 //Added by qt3to4:
27 #include <QTextStream>
28 #include <kdebug.h>
30 #include <kdeversion.h>
31 #define macroExpander
32 #include <kmacroexpander.h>
34 Speech::Speech() {
37 Speech::~Speech() {
40 QString Speech::prepareCommand (QString command, const QString &text,
41 const QString &filename, const QString &language) {
42 #ifdef macroExpander
43 QHash<QChar,QString> map;
44 map['t'] = text;
45 map['f'] = filename;
46 map['l'] = language;
47 return KMacroExpander::expandMacrosShellQuote (command, map);
48 #else
49 QStack<bool> stack; // saved isdoublequote values during parsing of braces
50 bool issinglequote=false; // inside '...' ?
51 bool isdoublequote=false; // inside "..." ?
52 int noreplace=0; // nested braces when within ${...}
53 QString escText = K3ShellProcess::quote(text);
55 // character sequences that change the state or need to be otherwise processed
56 QRegExp re_singlequote("('|%%|%t|%f|%l)");
57 QRegExp re_doublequote("(\"|\\\\|`|\\$\\(|\\$\\{|%%|%t|%f|%l)");
58 QRegExp re_noquote ("('|\"|\\\\|`|\\$\\(|\\$\\{|\\(|\\{|\\)|\\}|%%|%t|%f|%l)");
60 // parse the command:
61 for (int i = re_noquote.search(command);
62 i != -1;
63 i = (issinglequote?re_singlequote.search(command,i)
64 :isdoublequote?re_doublequote.search(command,i)
65 :re_noquote.search(command,i))
67 // while there are character sequences that need to be processed
69 if ((command[i]=='(') || (command[i]=='{')) { // (...) or {...}
70 // assert(isdoublequote == false)
71 stack.push(isdoublequote);
72 if (noreplace > 0)
73 // count nested braces when within ${...}
74 noreplace++;
75 i++;
77 else if (command[i]=='$') { // $(...) or ${...}
78 stack.push(isdoublequote);
79 isdoublequote = false;
80 if ((noreplace > 0) || (command[i+1]=='{'))
81 // count nested braces when within ${...}
82 noreplace++;
83 i+=2;
85 else if ((command[i]==')') || (command[i]=='}')) {
86 // $(...) or (...) or ${...} or {...}
87 if (!stack.isEmpty())
88 isdoublequote = stack.pop();
89 else
90 qWarning("Parse error.");
91 if (noreplace > 0)
92 // count nested braces when within ${...}
93 noreplace--;
94 i++;
96 else if (command[i]=='\'') {
97 issinglequote=!issinglequote;
98 i++;
100 else if (command[i]=='"') {
101 isdoublequote=!isdoublequote;
102 i++;
104 else if (command[i]=='\\')
105 i+=2;
106 else if (command[i]=='`') {
107 // Replace all `...` with safer $(...)
108 command.replace (i, 1, "$(");
109 QRegExp re_backticks("(`|\\\\`|\\\\\\\\|\\\\\\$)");
110 for (int i2=re_backticks.search(command,i+2);
111 i2!=-1;
112 i2=re_backticks.search(command,i2)
115 if (command[i2] == '`') {
116 command.replace (i2, 1, ")");
117 i2=command.length(); // leave loop
119 else {
120 // remove backslash and ignore following character
121 command.remove (i2, 1);
122 i2++;
125 // Leave i unchanged! We need to process "$("
127 else if (noreplace > 0) { // do not replace macros within ${...}
128 if (issinglequote)
129 i+=re_singlequote.matchedLength();
130 else if (isdoublequote)
131 i+=re_doublequote.matchedLength();
132 else
133 i+=re_noquote.matchedLength();
135 else { // replace macro
136 QString match, v;
138 // get match
139 if (issinglequote)
140 match=re_singlequote.cap();
141 else if (isdoublequote)
142 match=re_doublequote.cap();
143 else
144 match=re_noquote.cap();
146 // substitute %variables
147 if (match=="%t")
148 v = escText;
149 else if (match=="%f")
150 v = filename;
151 else if (match=="%%")
152 v = "%";
153 else if (match=="%l")
154 v = language;
156 // %variable inside of a quote?
157 if (isdoublequote)
158 v='"'+v+'"';
159 else if (issinglequote)
160 v='\''+v+'\'';
162 command.replace (i, match.length(), v);
163 i+=v.length();
166 return command;
167 #endif
170 void Speech::speak(QString command, bool stdIn, const QString &text, const QString &language, int encoding, QTextCodec *codec) {
171 if (text.length () > 0) {
172 // 1. prepare the text:
173 // 1.a) encode the text
174 QTextStream ts (encText, QIODevice::WriteOnly);
175 if (encoding == Local)
176 ts.setEncoding (QTextStream::Locale);
177 else if (encoding == Latin1)
178 ts.setEncoding (QTextStream::Latin1);
179 else if (encoding == Unicode)
180 ts.setEncoding (QTextStream::Unicode);
181 else
182 ts.setCodec (codec);
183 ts << text;
185 // 1.b) create a temporary file for the text
186 tempFile.open();
187 QTextStream fs ( &tempFile );
188 if (encoding == Local)
189 fs.setEncoding (QTextStream::Locale);
190 else if (encoding == Latin1)
191 fs.setEncoding (QTextStream::Latin1);
192 else if (encoding == Unicode)
193 fs.setEncoding (QTextStream::Unicode);
194 else
195 fs.setCodec (codec);
196 fs << text;
197 fs << endl;
198 QString filename = tempFile.fileName();
199 tempFile.flush();
201 // 2. prepare the command:
202 command = prepareCommand (command, encText, filename, language);
205 // 3. create a new process
206 process << command;
207 connect(&process, SIGNAL(processExited(K3Process *)), this, SLOT(processExited(K3Process *)));
208 connect(&process, SIGNAL(wroteStdin(K3Process *)), this, SLOT(wroteStdin(K3Process *)));
209 connect(&process, SIGNAL(receivedStdout(K3Process *, char *, int)), this, SLOT(receivedStdout(K3Process *, char *, int)));
210 connect(&process, SIGNAL(receivedStderr(K3Process *, char *, int)), this, SLOT(receivedStderr(K3Process *, char *, int)));
212 // 4. start the process
213 if (stdIn) {
214 process.start(K3Process::NotifyOnExit, K3Process::All);
215 if (encText.size() > 0)
216 process.writeStdin(encText, encText.size());
217 else
218 process.closeStdin();
220 else
221 process.start(K3Process::NotifyOnExit, K3Process::AllOutput);
225 void Speech::receivedStdout (K3Process *, char *buffer, int buflen) {
226 kDebug() << QString::fromLatin1(buffer, buflen) + '\n';
228 void Speech::receivedStderr (K3Process *, char *buffer, int buflen) {
229 kDebug() << QString::fromLatin1(buffer, buflen) + '\n';
232 void Speech::wroteStdin(K3Process *) {
233 process.closeStdin();
236 void Speech::processExited(K3Process *) {
237 delete this;
240 #include "speech.moc"