static QByteArrayList argumentList(const DwarfDie *die) { QByteArrayList args; foreach (const auto child, die->children()) { if (child->tag() == DW_TAG_formal_parameter) { args.push_back(child->typeName()); } } return args; }
void LyricsParser_KFN::parse(QIODevice * file, LyricsLoader::Container& output, LyricsLoader::Properties &properties) { // Parse the song.ini and fill up the sync and text arrays QByteArrayList texts; QList< int > syncs; // Analyze each line int idx_text = 0, idx_sync = 0; QByteArrayList lines = load( file ).split( '\n' ); bool inGeneral = false; for ( int i = 0; i < lines.size(); i++ ) { QByteArray line = lines[i]; // Section detector if ( line.startsWith( '[' ) && line.endsWith( ']') ) { inGeneral = (line == "[General]"); continue; } if ( inGeneral ) { if ( line.startsWith( "Title=" ) ) { QString v = QString::fromUtf8( line.mid(6) ).trimmed(); if ( !v.isEmpty() ) properties[ LyricsLoader::PROP_TITLE ] = v; } if ( line.startsWith( "Artist=" ) ) { QString v = QString::fromUtf8( line.mid(7) ).trimmed(); if ( !v.isEmpty() ) properties[ LyricsLoader::PROP_ARTIST ] = v; } } // Try to match the sync first char matchbuf[128]; sprintf( matchbuf, "Sync%d=", idx_sync ); if ( line.startsWith( matchbuf ) ) { idx_sync++; // Syncs are split by comma QByteArrayList values = line.mid( strlen(matchbuf) ).split( ',' ); for ( int v = 0; v < values.size(); v++ ) syncs.push_back( values[v].toInt() ); } // Now the text sprintf( matchbuf, "Text%d=", idx_text ); if ( line.startsWith( matchbuf ) ) { idx_text++; QByteArray textvalue = line.mid( strlen(matchbuf) ); if ( !textvalue.isEmpty() ) { // Text is split by word and optionally by the slash QByteArrayList values = textvalue.split(' '); for ( int v = 0; v < values.size(); v++ ) { QByteArrayList morevalues = values[v].split( '/' ); for ( int vv = 0; vv < morevalues.size(); vv++ ) texts.push_back( morevalues[vv] ); // We split by space, so add it at the end of each word texts.last() = texts.last() + " "; } } // Line matched, so make it a line if ( texts.size() > 2 && texts[ texts.size() - 2 ] != "\n" ) texts.push_back( "\n" ); } } int curr_sync = 0; bool has_linefeed = false; int lines_no_block = 0; int lastsync = -1; // The original timing marks are not necessarily sorted, so we add them into a map // and then output them from that map QMap< int, QByteArray > sortedLyrics; for ( int i = 0; i < texts.size(); i++ ) { if ( texts[i] == "\n" ) { if ( lastsync == -1 ) continue; if ( has_linefeed ) lines_no_block = 0; else if ( ++lines_no_block > 6 ) { lines_no_block = 0; sortedLyrics[ lastsync ] += "\n"; } has_linefeed = true; sortedLyrics[ lastsync ] += "\n"; continue; } else has_linefeed = false; // Get the time if we have it if ( curr_sync >= syncs.size() ) continue; lastsync = syncs[ curr_sync++ ]; sortedLyrics.insert( lastsync, texts[i] ); } // Generate the content for encoding detection QByteArray lyricsForEncoding; for ( QMap< int, QByteArray >::const_iterator it = sortedLyrics.begin(); it != sortedLyrics.end(); ++it ) lyricsForEncoding.append( it.value() ); // Detect the encoding QTextCodec * codec = detectEncoding( lyricsForEncoding, properties ); for ( QMap< int, QByteArray >::const_iterator it = sortedLyrics.begin(); it != sortedLyrics.end(); ++it ) { qint64 timing = it.key() * 10; Lyric lyr( timing, codec->toUnicode( it.value() ) ); // Last line? if ( lyr.text.endsWith( '\n') ) { // Remove the \n lyr.text.chop( 1 ); output.push_back( lyr ); // and add an empty lyric output.push_back( Lyric( timing ) ); } else { output.push_back( lyr ); } } }
QVariantMap System::exec(const QString & prog, const QStringList & args) { pid_t pid = fork(); if (pid == 0) { int cargs_len = args.length() + 2; char * cargs[cargs_len]; cargs[cargs_len - 1] = NULL; QByteArrayList as; as.push_back(prog.toLocal8Bit()); std::transform(args.begin(), args.end(), std::back_inserter(as), [](const QString & s) { return s.toLocal8Bit(); }); for (int i = 0; i < as.length(); ++i) { cargs[i] = as[i].data(); } execvp(cargs[0], cargs); // in case execvp fails, terminate the child process immediately _exit(errno); } else if (pid < 0) { goto fail; } else { sigset_t mask; sigset_t orig_mask; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); if (sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0) { goto fail; } struct timespec timeout; timeout.tv_sec = 0; timeout.tv_nsec = 10 * 1000 * 1000; while (true) { int ret = sigtimedwait(&mask, NULL, &timeout); if (ret < 0) { if (errno == EAGAIN) { // timeout goto win; } else { // error goto fail; } } else { if (errno == EINTR) { // not SIGCHLD continue; } else { siginfo_t si; if (waitid(P_PID, pid, &si, WEXITED) < 0) { goto fail; } else { return { { "errno", si.si_status } , { "error", strerror(si.si_status) } }; } } } } } win: return {}; fail: return { { "errno", errno }, { "error", strerror(errno) } }; }