Example #1
0
/**
* Say or Synthesize text.
* @param inputText               The text that shall be spoken
* @param suggestedFilename       If not Null, synthesize only to this filename, otherwise
*                                synthesize and audibilize the text.
* @param userCmd                 The program that shall be executed for speaking
* @param stdIn                   True if the program shall recieve its data via standard input
* @param codec                   The QTextCodec if encoding==UseCodec
* @param language                The language code (used for the %l macro)
*/
void CommandProc::synth(const QString& inputText, const QString& suggestedFilename,
    const QString& userCmd, bool stdIn, QTextCodec *codec, QString& language)
{
    if (m_commandProc)
    {
        if (m_commandProc->isRunning()) m_commandProc->kill();
        delete m_commandProc;
        m_commandProc = 0;
        m_synthFilename = QString::null;
        if (!m_textFilename.isNull()) QFile::remove(m_textFilename);
        m_textFilename = QString::null;
    }
    QString command = userCmd;
    QString text = inputText.stripWhiteSpace();
    if (text.isEmpty()) return;
     // 1. prepare the text:
     // 1.a) encode the text
    text += "\n";
    QCString encodedText;
    if (codec)
        encodedText = codec->fromUnicode(text);
    else
        encodedText = text.latin1();  // Should not happen, but just in case.

    // 1.b) quote the text as one parameter
    QString escText = KShellProcess::quote(text);

    // 1.c) create a temporary file for the text, if %f macro is used.
    if (command.contains("%f"))
    {
        KTempFile tempFile(locateLocal("tmp", "commandplugin-"), ".txt");
        QTextStream* fs = tempFile.textStream();
        fs->setCodec(codec);
        *fs << text;
        *fs << endl;
        m_textFilename = tempFile.file()->name();
        tempFile.close();
    } else m_textFilename = QString::null;

    // 2. replace variables with values
    QValueStack<bool> stack;
    bool issinglequote=false;
    bool isdoublequote=false;
    int noreplace=0;
    QRegExp re_noquote("(\"|'|\\\\|`|\\$\\(|\\$\\{|\\(|\\{|\\)|\\}|%%|%t|%f|%l|%w)");
    QRegExp re_singlequote("('|%%|%t|%f|%l|%w)");
    QRegExp re_doublequote("(\"|\\\\|`|\\$\\(|\\$\\{|%%|%t|%f|%l|%w)");

    for	( int i = re_noquote.search(command);
        i != -1;
        i = (issinglequote?re_singlequote.search(command,i)
            :isdoublequote?re_doublequote.search(command,i)
            :re_noquote.search(command,i))
    )
    {
        if ((command[i]=='(') || (command[i]=='{')) // (...) or {...}
        {
            // assert(isdoublequote == false)
            stack.push(isdoublequote);
            if (noreplace > 0)
                // count nested braces when within ${...}
                noreplace++;
            i++;
        }
        else if (command[i]=='$')
        {
            stack.push(isdoublequote);
            isdoublequote = false;
            if ((noreplace > 0) || (command[i+1]=='{'))
                // count nested braces when within ${...}
                noreplace++;
            i+=2;
        }
        else if ((command[i]==')') || (command[i]=='}'))
            // $(...) or (...) or ${...} or {...}
        {
            if (!stack.isEmpty())
                isdoublequote = stack.pop();
            else
                qWarning("Parse error.");
            if (noreplace > 0)
                // count nested braces when within ${...}
                noreplace--;
            i++;
        }
        else if (command[i]=='\'')
        {
            issinglequote=!issinglequote;
            i++;
        }
        else if (command[i]=='"')
        {
            isdoublequote=!isdoublequote;
            i++;
        }
        else if (command[i]=='\\')
            i+=2;
        else if (command[i]=='`')
        {
            // Replace all `...` with safer $(...)
            command.replace (i, 1, "$(");
            QRegExp re_backticks("(`|\\\\`|\\\\\\\\|\\\\\\$)");
            for (	int i2=re_backticks.search(command,i+2);
                i2!=-1;
                i2=re_backticks.search(command,i2)
            )
            {
                if (command[i2] == '`')
                {
                    command.replace (i2, 1, ")");
                    i2=command.length(); // leave loop
                }
                else
                {   // remove backslash and ignore following character
                    command.remove (i2, 1);
                    i2++;
                }
            }
            // Leave i unchanged! We need to process "$("
        }
        else if (noreplace == 0) // do not replace macros within ${...}
        {
            QString match, v;

            // get match
            if (issinglequote)
                match=re_singlequote.cap();
            else if (isdoublequote)
                match=re_doublequote.cap();
            else
                match=re_noquote.cap();

            // substitue %variables
            if (match=="%%")
                v="%";
            else if (match=="%t")
                v=escText;
            else if (match=="%f")
                v=m_textFilename;
            else if (match=="%l")
                v=language;
            else if (match=="%w")
                v = suggestedFilename;

            // %variable inside of a quote?
            if (isdoublequote)
                v='"'+v+'"';
            else if (issinglequote)
                v="'"+v+"'";

            command.replace (i, match.length(), v);
            i+=v.length();
        }
        else
        {
            if (issinglequote)
                i+=re_singlequote.matchedLength();
            else if (isdoublequote)
                i+=re_doublequote.matchedLength();
            else
                i+=re_noquote.matchedLength();
        }
    }

    // 3. create a new process
    kdDebug() << "CommandProc::synth: running command: " << command << endl;
    m_commandProc = new KProcess;
    m_commandProc->setUseShell(true);
    m_commandProc->setEnvironment("LANG", language + "." + codec->mimeName());
    m_commandProc->setEnvironment("LC_CTYPE", language + "." + codec->mimeName());
    *m_commandProc << command;
    connect(m_commandProc, SIGNAL(processExited(KProcess*)),
        this, SLOT(slotProcessExited(KProcess*)));
    connect(m_commandProc, SIGNAL(receivedStdout(KProcess*, char*, int)),
        this, SLOT(slotReceivedStdout(KProcess*, char*, int)));
    connect(m_commandProc, SIGNAL(receivedStderr(KProcess*, char*, int)),
        this, SLOT(slotReceivedStderr(KProcess*, char*, int)));
    connect(m_commandProc, SIGNAL(wroteStdin(KProcess*)),
        this, SLOT(slotWroteStdin(KProcess* )));

    // 4. start the process

    if (suggestedFilename.isNull())
        m_state = psSaying;
    else
    {
        m_synthFilename = suggestedFilename;
        m_state = psSynthing;
    }
    if (stdIn) {
        m_commandProc->start(KProcess::NotifyOnExit, KProcess::All);
        if (encodedText.length() > 0)
            m_commandProc->writeStdin(encodedText, encodedText.length());
        else
            m_commandProc->closeStdin();
    }
    else
        m_commandProc->start(KProcess::NotifyOnExit, KProcess::AllOutput);
}
Example #2
0
QString Speech::prepareCommand(QString command, const QString &text,
                               const QString &filename, const QString &language)
{
#ifdef macroExpander
    QHash<QChar, QString> map;
    map[QLatin1Char('t')] = text;
    map[QLatin1Char('f')] = filename;
    map[QLatin1Char('l')] = language;
    return KMacroExpander::expandMacrosShellQuote(command, map);
#else
    QStack<bool> stack;  // saved isdoublequote values during parsing of braces
    bool issinglequote = false; // inside '...' ?
    bool isdoublequote = false; // inside "..." ?
    int noreplace = 0; // nested braces when within ${...}
    QString escText = K3ShellProcess::quote(text);

    // character sequences that change the state or need to be otherwise processed
    QRegExp re_singlequote("('|%%|%t|%f|%l)");
    QRegExp re_doublequote("(\"|\\\\|`|\\$\\(|\\$\\{|%%|%t|%f|%l)");
    QRegExp re_noquote("('|\"|\\\\|`|\\$\\(|\\$\\{|\\(|\\{|\\)|\\}|%%|%t|%f|%l)");

    // parse the command:
    for (int i = re_noquote.search(command);
         i != -1;
         i = (issinglequote ? re_singlequote.search(command, i)
              : isdoublequote ? re_doublequote.search(command, i)
              : re_noquote.search(command, i))
        )
        // while there are character sequences that need to be processed
    {
        if ((command[i] == '(') || (command[i] == '{')) { // (...) or {...}
            // assert(isdoublequote == false)
            stack.push(isdoublequote);
            if (noreplace > 0)
                // count nested braces when within ${...}
                noreplace++;
            i++;
        } else if (command[i] == '$') { // $(...) or ${...}
            stack.push(isdoublequote);
            isdoublequote = false;
            if ((noreplace > 0) || (command[i + 1] == '{'))
                // count nested braces when within ${...}
                noreplace++;
            i += 2;
        } else if ((command[i] == ')') || (command[i] == '}')) {
            // $(...) or (...) or ${...} or {...}
            if (!stack.isEmpty())
                isdoublequote = stack.pop();
            else
                qWarning("Parse error.");
            if (noreplace > 0)
                // count nested braces when within ${...}
                noreplace--;
            i++;
        } else if (command[i] == '\'') {
            issinglequote = !issinglequote;
            i++;
        } else if (command[i] == '"') {
            isdoublequote = !isdoublequote;
            i++;
        } else if (command[i] == '\\')
            i += 2;
        else if (command[i] == '`') {
            // Replace all `...` with safer $(...)
            command.replace(i, 1, "$(");
            QRegExp re_backticks("(`|\\\\`|\\\\\\\\|\\\\\\$)");
            for (int i2 = re_backticks.search(command, i + 2);
                 i2 != -1;
                 i2 = re_backticks.search(command, i2)
                ) {
                if (command[i2] == '`') {
                    command.replace(i2, 1, ")");
                    i2 = command.length(); // leave loop
                } else {
                    // remove backslash and ignore following character
                    command.remove(i2, 1);
                    i2++;
                }
            }
            // Leave i unchanged! We need to process "$("
        } else if (noreplace > 0) { // do not replace macros within ${...}
            if (issinglequote)
                i += re_singlequote.matchedLength();
            else if (isdoublequote)
                i += re_doublequote.matchedLength();
            else
                i += re_noquote.matchedLength();
        } else { // replace macro
            QString match, v;

            // get match
            if (issinglequote)
                match = re_singlequote.cap();
            else if (isdoublequote)
                match = re_doublequote.cap();
            else
                match = re_noquote.cap();

            // substitute %variables
            if (match == "%t")
                v = escText;
            else if (match == "%f")
                v = filename;
            else if (match == "%%")
                v = "%";
            else if (match == "%l")
                v = language;

            // %variable inside of a quote?
            if (isdoublequote)
                v = '"' + v + '"';
            else if (issinglequote)
                v = '\'' + v + '\'';

            command.replace(i, match.length(), v);
            i += v.length();
        }
    }
    return command;
#endif
}