1 /***************************************************************************
2 speech.cpp - description
5 copyright : (C) 2002 by Gunnar Schmi Dt
6 email : kmouth@schmi-dt.de
7 ***************************************************************************/
9 /***************************************************************************
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. *
16 ***************************************************************************/
26 #include <QTextStream>
29 #include <kdeversion.h>
31 #include <kmacroexpander.h>
39 QString
Speech::prepareCommand (QString command
, const QString
&text
,
40 const QString
&filename
, const QString
&language
) {
42 QHash
<QChar
,QString
> map
;
46 return KMacroExpander::expandMacrosShellQuote (command
, map
);
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)");
60 for (int i
= re_noquote
.search(command
);
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
);
72 // count nested braces when within ${...}
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 ${...}
84 else if ((command
[i
]==')') || (command
[i
]=='}')) {
85 // $(...) or (...) or ${...} or {...}
87 isdoublequote
= stack
.pop();
89 qWarning("Parse error.");
91 // count nested braces when within ${...}
95 else if (command
[i
]=='\'') {
96 issinglequote
=!issinglequote
;
99 else if (command
[i
]=='"') {
100 isdoublequote
=!isdoublequote
;
103 else if (command
[i
]=='\\')
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);
111 i2
=re_backticks
.search(command
,i2
)
114 if (command
[i2
] == '`') {
115 command
.replace (i2
, 1, ")");
116 i2
=command
.length(); // leave loop
119 // remove backslash and ignore following character
120 command
.remove (i2
, 1);
124 // Leave i unchanged! We need to process "$("
126 else if (noreplace
> 0) { // do not replace macros within ${...}
128 i
+=re_singlequote
.matchedLength();
129 else if (isdoublequote
)
130 i
+=re_doublequote
.matchedLength();
132 i
+=re_noquote
.matchedLength();
134 else { // replace macro
139 match
=re_singlequote
.cap();
140 else if (isdoublequote
)
141 match
=re_doublequote
.cap();
143 match
=re_noquote
.cap();
145 // substitute %variables
148 else if (match
=="%f")
150 else if (match
=="%%")
152 else if (match
=="%l")
155 // %variable inside of a quote?
158 else if (issinglequote
)
161 command
.replace (i
, match
.length(), v
);
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
);
184 // 1.b) create a temporary file for the text
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
);
197 QString filename
= tempFile
.fileName();
200 // 2. prepare the command:
201 command
= prepareCommand (command
, encText
, filename
, language
);
204 // 3. create a new process
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
213 process
.start(K3Process::NotifyOnExit
, K3Process::All
);
214 if (encText
.size() > 0)
215 process
.writeStdin(encText
, encText
.size());
217 process
.closeStdin();
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
*) {
239 #include "speech.moc"