1 /*
2 this code is Public Domain
3 Peter Semiletov
4 */
5
6
7
8 #include <QTextStream>
9 #include <QTextCodec>
10 #include <QDebug>
11 #include <QDir>
12 #include <QImageReader>
13 #include <QImage>
14 #include <QProcess>
15 #include <QApplication>
16
17 #include "utils.h"
18
19 using namespace std;
20
21 bool boring;
22
23
24 /* file utils */
25
has_css_file(const QString & path)26 bool has_css_file (const QString &path)
27 {
28 if (path.isEmpty())
29 return false;
30
31 QDir d (path);
32 QStringList l = d.entryList();
33
34 for (int i = 0; i < l.size(); i++)
35 {
36 if (l.at(i).endsWith(".css"))
37 return true;
38 }
39
40 return false;
41 }
42
43
guess_enc_for_file(const QString & fname)44 QString guess_enc_for_file (const QString &fname)
45 {
46 if (fname.isEmpty())
47 return QString();
48
49 QString enc = "UTF-8";
50
51 QProcess p;
52 p.start ("enca", QStringList() << "-i" << fname);
53
54 if (! p.waitForStarted() || ! p.waitForFinished() )
55 return "err";
56
57 QString s = p.readAllStandardOutput();
58 if (! s.isEmpty())
59 enc = s.trimmed();
60
61 return enc;
62 }
63
64
file_is_writable(const QString & fname)65 bool file_is_writable (const QString &fname)
66 {
67 if (fname.isEmpty())
68 return false;
69
70 QFile f (fname);
71 return f.isWritable();
72 }
73
74
file_is_readable(const QString & fname)75 bool file_is_readable (const QString &fname)
76 {
77 if (fname.isEmpty())
78 return false;
79
80 QFile f (fname);
81 return f.isReadable();
82 }
83
84
path_is_file(const QString & fname)85 bool path_is_file (const QString &fname)
86 {
87 if (fname.isEmpty())
88 return false;
89
90 QFileInfo fi (fname);
91 return fi.isFile();
92 }
93
94
path_is_dir(const QString & fname)95 bool path_is_dir (const QString &fname)
96 {
97 if (fname.isEmpty())
98 return false;
99
100 QFileInfo fi (fname);
101 return fi.isDir();
102 }
103
104
path_is_abs(const QString & fname)105 bool path_is_abs (const QString &fname)
106 {
107 if (fname.isEmpty())
108 return false;
109
110 if (fname[0] == '/' || fname.indexOf (':') == 1)
111 return true;
112 else
113 return false;
114 }
115
116
dir_exists(const QString & path)117 bool dir_exists (const QString &path)
118 {
119 if (path.isEmpty())
120 return false;
121
122 QDir d (path);
123 return d.exists();
124 }
125
126
file_exists(const QString & fileName)127 bool file_exists (const QString &fileName)
128 {
129 if (fileName.isEmpty())
130 return false;
131
132 return QFile::exists (fileName);
133 }
134
135
change_file_ext(const QString & s,const QString & ext)136 QString change_file_ext (const QString &s, const QString &ext)
137 {
138 int i = s.lastIndexOf (".");
139 if (i == -1)
140 return (s + "." + ext);
141
142 QString r (s);
143 r.truncate (++i);
144
145 r.append (ext);
146 return r;
147 }
148
149
file_get_ext(const QString & file_name)150 QString file_get_ext (const QString &file_name)
151 {
152 if (file_name.isEmpty())
153 return QString();
154
155 /* int i = file_name.lastIndexOf (".");
156 if (i == -1)
157 return QString();
158
159 return file_name.mid (i + 1).toLower();*/
160
161 QFileInfo fi (file_name);
162 return fi.completeSuffix();
163 }
164
165
read_dir_entries(const QString & path)166 QStringList read_dir_entries (const QString &path)
167 {
168 QDir dir (path);
169 return dir.entryList (QDir::AllEntries | QDir::NoDotAndDotDot);
170 }
171
172
173 /* io utils */
174
qstring_save(const QString & fileName,const QString & data,const char * enc)175 bool qstring_save (const QString &fileName, const QString &data, const char *enc)
176 {
177 if (fileName.isEmpty())
178 return false;
179
180 QFile file (fileName);
181 if (! file.open (QFile::WriteOnly))
182 return false;
183
184 QTextCodec *codec = QTextCodec::codecForName (enc);
185 QByteArray ba = codec->fromUnicode(data);
186
187 file.write(ba);
188 file.close();
189
190 return true;
191 }
192
193
qstring_load(const QString & fileName,const char * enc)194 QString qstring_load (const QString &fileName, const char *enc)
195 {
196 if (fileName.isEmpty())
197 return QString();
198
199 QFile file (fileName);
200
201 if (! file.open (QFile::ReadOnly))
202 return QString();
203
204 QByteArray ba = file.readAll();
205 QTextCodec *codec = QTextCodec::codecForName(enc);
206
207 file.close();
208
209 return codec->toUnicode(ba);
210 }
211
212
qstring_load_first_line(const QString & fileName)213 QString qstring_load_first_line (const QString &fileName)
214 {
215 if (fileName.isEmpty())
216 return QString();
217
218 QFile file (fileName);
219
220 if (! file.open (QFile::ReadOnly | QFile::Text))
221 return QString();
222
223 QTextStream in(&file);
224
225 return in.readLine();
226 }
227
228
file_load(const QString & fileName)229 QByteArray file_load (const QString &fileName)
230 {
231 if (fileName.isEmpty())
232 return QByteArray();
233
234 QFile file (fileName);
235 QByteArray b;
236
237 if (! file.open (QFile::ReadOnly))
238 return b;
239
240 b = file.readAll();
241
242 return b;
243 }
244
245
246 /* string/stringlist utils */
247
strlist_swap(QStringList & l,int a,int b)248 void strlist_swap (QStringList &l, int a, int b)
249 {
250 QString t = l[a];
251 l[a] = l[b];
252 l[b] = t;
253 }
254
255
string_between(const QString & source,const QString & sep1,const QString & sep2)256 QString string_between (const QString &source,
257 const QString &sep1,
258 const QString &sep2)
259 {
260 QString result;
261 int pos1 = source.indexOf (sep1);
262 if (pos1 == -1)
263 return result;
264
265 int pos2 = source.indexOf (sep2, pos1 + sep1.size());
266 if (pos2 == -1)
267 return result;
268
269 pos1 += sep1.size();
270
271 result = source.mid (pos1, pos2 - pos1);
272 return result;
273 }
274
275
char_is_bad(const QChar & c)276 bool char_is_bad (const QChar &c)
277 {
278 if (! c.isNull() && ! c.isLetter())
279 return true;
280
281 return false;
282 }
283
284
qstring_list_print(const QStringList & l)285 void qstring_list_print (const QStringList &l)
286 {
287 for (int i = 0; i < l.size(); i++)
288 qDebug() << l[i];
289 }
290
291
bytearray_to_stringlist(const QList<QByteArray> & a)292 QStringList bytearray_to_stringlist (const QList<QByteArray> &a)
293 {
294 QStringList r;
295
296 for (int i = 0; i < a.size(); i++)
297 r.append (a.at(i).data());
298
299 return r;
300 }
301
302
303 /* hash utils */
304
hash_get_val(QHash<QString,QString> & h,const QString & key,const QString & def_val)305 QString hash_get_val (QHash<QString, QString> &h,
306 const QString &key,
307 const QString &def_val)
308 {
309 QString result = h.value (key);
310 if (result.isEmpty())
311 {
312 result = def_val;
313 h.insert (key, def_val);
314 }
315
316 return result;
317 }
318
319
qstring_load_value(const QString & fileName,const QString & key,const QString & def)320 QString qstring_load_value (const QString &fileName, const QString &key, const QString &def)
321 {
322 QHash <QString, QString> h = hash_load_keyval (fileName);
323 return hash_get_val (h, key, def);
324 }
325
326
hash_load_keyval(const QString & fname)327 QHash <QString, QString> hash_load_keyval (const QString &fname)
328 {
329 QHash <QString, QString> result;
330
331 if (! file_exists (fname))
332 return result;
333
334 QStringList l = qstring_load (fname).split ("\n");
335
336 for (QList <QString>::iterator i = l.begin(); i != l.end(); ++i)
337 {
338 QStringList sl = i->split ("=");
339 if (sl.size() > 1)
340 result.insert (sl.at(0), sl.at(1));
341 }
342
343 return result;
344 }
345
346
hash_save_keyval(const QString & fname,const QHash<QString,QString> & h)347 void hash_save_keyval (const QString &fname, const QHash <QString, QString> &h)
348 {
349 QFile::remove (fname);
350
351 QStringList l;
352
353 QHash<QString, QString>::const_iterator i = h.constBegin();
354 while (i != h.constEnd())
355 {
356 l+= (i.key() + "=" + i.value());
357 ++i;
358 }
359
360 qstring_save (fname, l.join ("\n"));
361 }
362
363
364 /* image utils */
365
is_image(const QString & filename)366 bool is_image (const QString &filename)
367 {
368 if (filename.isEmpty())
369 return false;
370
371 QList <QByteArray> a = QImageReader::supportedImageFormats();
372
373 for (QList <QByteArray>::iterator i = a.begin(); i != a.end(); ++i)
374 {
375 QString t (i->data());
376 if (filename.endsWith (t.prepend ("."), Qt::CaseInsensitive))
377 return true;
378 }
379
380 return false;
381 }
382
383
get_insert_image(const QString & file_name,const QString & full_path,const QString & markup_mode)384 QString get_insert_image (const QString &file_name, const QString &full_path, const QString &markup_mode)
385 {
386 if (! is_image (full_path))
387 return QString();
388
389 QFileInfo inf (file_name);
390 QDir dir (inf.absolutePath());
391
392 QImage img;
393 img.load (full_path);
394 QString result;
395
396 if (markup_mode == "HTML")
397 result = QString ("<img src=\"%1\" alt=\"\" width=\"%2\" height=\"%3\">").arg (
398 dir.relativeFilePath (full_path)).arg (img.width()).arg (img.height());
399 else
400 if (markup_mode == "XHTML")
401 result = QString ("<img src=\"%1\" border=\"0\" alt=\"\" width=\"%2\" height=\"%3\" />").arg (
402 dir.relativeFilePath (full_path)).arg (img.width()).arg (img.height());
403 else
404 if (markup_mode == "Docbook")
405 result = QString ("<mediaobject><imageobject>\n<imagedata fileref=\"%1\"/>\n</imageobject></mediaobject>").arg (
406 dir.relativeFilePath (full_path)) ;
407 else
408 if (markup_mode == "LaTeX")
409 result = QString ("\\includegraphics{%1}").arg (dir.relativeFilePath (full_path));
410 else
411 if (markup_mode == "Lout")
412 result = QString ("@IncludeGraphic {%1}").arg (dir.relativeFilePath (full_path));
413 else
414 if (markup_mode == "Markdown")
415 result = QString ("![alt_text]({%1})").arg (dir.relativeFilePath (full_path));
416
417 return result;
418 }
419
420
421 /* class functions */
422
iterate(QFileInfo & fi)423 void CFilesList::iterate (QFileInfo &fi)
424 {
425 qApp->processEvents();
426
427 if (boring)
428 return;
429
430 if (fi.isDir())
431 {
432 QDir d (fi.absoluteFilePath());
433 QFileInfoList lfi= d.entryInfoList (QDir::Dirs | QDir::Files | QDir::Readable | QDir::NoDotAndDotDot);
434 for (int i = 0; i < lfi.count(); i++)
435 iterate (lfi[i]);
436 }
437 else
438 if (fi.isFile())
439 list.append (fi.absoluteFilePath());
440 }
441
442
get(const QString & path)443 void CFilesList::get (const QString &path)
444 {
445 if (path.isEmpty())
446 return;
447
448 list.clear();
449 QDir d (path);
450 QFileInfoList lfi= d.entryInfoList (QDir::Dirs | QDir::Files | QDir::Readable | QDir::NoDotAndDotDot);
451 for (int i = 0; i < lfi.count(); i++)
452 iterate (lfi[i]);
453 }
454
455
456
457 #if QT_VERSION < 0x050000
458 #define ADDTEXTTYPE(expr) patterns.push_back (QRegExp (expr, Qt::CaseInsensitive));
459 #else
460 #define ADDTEXTTYPE(expr) patterns.push_back (QRegularExpression (expr, QRegularExpression::CaseInsensitiveOption));
461 #endif
462
463
464
CFTypeChecker()465 CFTypeChecker::CFTypeChecker()
466 {
467
468 ADDTEXTTYPE (".*(readme|news|changelog|todo)$");
469 ADDTEXTTYPE ("^\\..*(rc)$");
470 ADDTEXTTYPE ("^.*\\.(txt|conf|md|ini|bat|cfg|sbv|log|odt|docx|kwd|fb2|fb2.zip|fbz|abw|rtf|epub|sxw)$");
471 ADDTEXTTYPE ("^.*\\.(cpp|c|h|hh|cxx|hpp|cc|m|mm)$");
472 ADDTEXTTYPE ("^.*\\.(htm|html|xml|xhtml|ts|osm|xsl)$");
473 #if defined(POPPLER_ENABLE)
474 ADDTEXTTYPE ("^.*\\.(pdf)$");
475 #endif
476 #if defined(DJVU_ENABLE)
477 ADDTEXTTYPE ("^.*\\.(djvu)$");
478 #endif
479
480
481 ADDTEXTTYPE ("^.*\\.(awk)$");
482 ADDTEXTTYPE ("^.*\\.(sh)$");
483 ADDTEXTTYPE ("^.*\\.(bas|bi|vbs|vbe)$");
484 ADDTEXTTYPE ("^.*\\.(d)$");
485 ADDTEXTTYPE ("^.*\\.(f|for|f90|f95)$");
486 ADDTEXTTYPE ("^.*\\.(java|js)$");
487 ADDTEXTTYPE ("^.*\\.(ly)$");
488 ADDTEXTTYPE ("^.*\\.(lout)$");
489 ADDTEXTTYPE ("^.*\\.(lua)$");
490 ADDTEXTTYPE ("^.*\\.(asm)$");
491 ADDTEXTTYPE ("^.*\\.(nsi)$");
492 ADDTEXTTYPE ("^.*\\.(pp|pas|dpr)$");
493 ADDTEXTTYPE ("^.*\\.(pl|pm)$");
494 ADDTEXTTYPE ("^.*\\.(php)$");
495 ADDTEXTTYPE ("^.*\\.(po)$");
496 ADDTEXTTYPE ("^.*\\.(py)$");
497 ADDTEXTTYPE ("^.*\\.(r)$");
498 ADDTEXTTYPE ("^.*\\.(sd7)$");
499 ADDTEXTTYPE ("^.*\\.(tex|lyx)$");
500 ADDTEXTTYPE ("^.*\\.(vala)$");
501 ADDTEXTTYPE ("^.*\\.(v)$");
502 ADDTEXTTYPE ("^.*\\.(wiki)$");
503 }
504
505
506
507 /*
508 CFTypeChecker::CFTypeChecker()
509 {
510
511 #if QT_VERSION < 0x050000
512
513 patterns.push_back (QRegExp (".*(readme|news|changelog|todo)$", Qt::CaseInsensitive));
514 patterns.push_back (QRegExp ("^\\..*(rc)$", Qt::CaseInsensitive));
515 patterns.push_back (QRegExp ("^.*\\.(txt|conf|md|ini|bat|cfg|sbv|log|odt|docx|kwd|fb2|abw|rtf|epub|sxw|fb2.zip)$", Qt::CaseInsensitive));
516 patterns.push_back (QRegExp ("^.*\\.(cpp|c|h|hh|cxx|hpp|cc|m|mm)$", Qt::CaseInsensitive));
517 patterns.push_back (QRegExp ("^.*\\.(htm|html|xml|xhtml|ts|osm|xsl)$", Qt::CaseInsensitive));
518
519 #if defined(POPPLER_ENABLE)
520 patterns.push_back (QRegExp ("^.*\\.(pdf)$", Qt::CaseInsensitive));
521 #endif
522
523 #if defined(DJVU_ENABLE)
524 patterns.push_back (QRegExp ("^.*\\.(djvu)$", Qt::CaseInsensitive));
525 #endif
526
527 patterns.push_back (QRegExp ("^.*\\.(awk)$", Qt::CaseInsensitive));
528 patterns.push_back (QRegExp ("^.*\\.(sh)$", Qt::CaseInsensitive));
529 patterns.push_back (QRegExp ("^.*\\.(bas|bi|vbs|vbe)$", Qt::CaseInsensitive));
530 patterns.push_back (QRegExp ("^.*\\.(d)$", Qt::CaseInsensitive));
531 patterns.push_back (QRegExp ("^.*\\.(f|for|f90|f95)$", Qt::CaseInsensitive));
532 patterns.push_back (QRegExp ("^.*\\.(java|js)$", Qt::CaseInsensitive));
533 patterns.push_back (QRegExp ("^.*\\.(ly)$", Qt::CaseInsensitive));
534 patterns.push_back (QRegExp ("^.*\\.(lout)$", Qt::CaseInsensitive));
535 patterns.push_back (QRegExp ("^.*\\.(lua)$", Qt::CaseInsensitive));
536 patterns.push_back (QRegExp ("^.*\\.(asm)$", Qt::CaseInsensitive));
537 patterns.push_back (QRegExp ("^.*\\.(nsi)$", Qt::CaseInsensitive));
538 patterns.push_back (QRegExp ("^.*\\.(pp|pas|dpr)$", Qt::CaseInsensitive));
539 patterns.push_back (QRegExp ("^.*\\.(pl|pm)$", Qt::CaseInsensitive));
540 patterns.push_back (QRegExp ("^.*\\.(php)$", Qt::CaseInsensitive));
541 patterns.push_back (QRegExp ("^.*\\.(po)$", Qt::CaseInsensitive));
542 patterns.push_back (QRegExp ("^.*\\.(py)$", Qt::CaseInsensitive));
543 patterns.push_back (QRegExp ("^.*\\.(r)$", Qt::CaseInsensitive));
544 patterns.push_back (QRegExp ("^.*\\.(sd7)$", Qt::CaseInsensitive));
545 patterns.push_back (QRegExp ("^.*\\.(tex|lyx)$", Qt::CaseInsensitive));
546 patterns.push_back (QRegExp ("^.*\\.(vala)$", Qt::CaseInsensitive));
547 patterns.push_back (QRegExp ("^.*\\.(v)$", Qt::CaseInsensitive));
548 patterns.push_back (QRegExp ("^.*\\.(wiki)$", Qt::CaseInsensitive));
549
550 #else
551
552 patterns.push_back (QRegularExpression (".*(readme|news|changelog|todo)$", QRegularExpression::CaseInsensitiveOption));
553 patterns.push_back (QRegularExpression ("^\\..*(rc)$", QRegularExpression::CaseInsensitiveOption));
554 patterns.push_back (QRegularExpression ("^.*\\.(txt|conf|md|ini|bat|cfg|sbv|log|odt|docx|kwd|fb2|abw|rtf|epub|sxw)$", QRegularExpression::CaseInsensitiveOption));
555 patterns.push_back (QRegularExpression ("^.*\\.(cpp|c|h|hh|cxx|hpp|cc|m|mm)$", QRegularExpression::CaseInsensitiveOption));
556 patterns.push_back (QRegularExpression ("^.*\\.(htm|html|xml|xhtml|ts|osm|xsl)$", QRegularExpression::CaseInsensitiveOption));
557
558 #if defined(POPPLER_ENABLE)
559 patterns.push_back (QRegularExpression ("^.*\\.(pdf)$", QRegularExpression::CaseInsensitiveOption));
560 #endif
561
562 #if defined(DJVU_ENABLE)
563 patterns.push_back (QRegularExpression ("^.*\\.(djvu)$", QRegularExpression::CaseInsensitiveOption));
564 #endif
565
566 patterns.push_back (QRegularExpression ("^.*\\.(awk)$", QRegularExpression::CaseInsensitiveOption));
567 patterns.push_back (QRegularExpression ("^.*\\.(sh)$", QRegularExpression::CaseInsensitiveOption));
568 patterns.push_back (QRegularExpression ("^.*\\.(bas|bi|vbs|vbe)$", QRegularExpression::CaseInsensitiveOption));
569 patterns.push_back (QRegularExpression ("^.*\\.(d)$", QRegularExpression::CaseInsensitiveOption));
570 patterns.push_back (QRegularExpression ("^.*\\.(f|for|f90|f95)$", QRegularExpression::CaseInsensitiveOption));
571 patterns.push_back (QRegularExpression ("^.*\\.(java|js)$", QRegularExpression::CaseInsensitiveOption));
572 patterns.push_back (QRegularExpression ("^.*\\.(ly)$", QRegularExpression::CaseInsensitiveOption));
573 patterns.push_back (QRegularExpression ("^.*\\.(lout)$", QRegularExpression::CaseInsensitiveOption));
574 patterns.push_back (QRegularExpression ("^.*\\.(lua)$", QRegularExpression::CaseInsensitiveOption));
575 patterns.push_back (QRegularExpression ("^.*\\.(asm)$", QRegularExpression::CaseInsensitiveOption));
576 patterns.push_back (QRegularExpression ("^.*\\.(nsi)$", QRegularExpression::CaseInsensitiveOption));
577 patterns.push_back (QRegularExpression ("^.*\\.(pp|pas|dpr)$", QRegularExpression::CaseInsensitiveOption));
578 patterns.push_back (QRegularExpression ("^.*\\.(pl|pm)$", QRegularExpression::CaseInsensitiveOption));
579 patterns.push_back (QRegularExpression ("^.*\\.(php)$", QRegularExpression::CaseInsensitiveOption));
580 patterns.push_back (QRegularExpression ("^.*\\.(po)$", QRegularExpression::CaseInsensitiveOption));
581 patterns.push_back (QRegularExpression ("^.*\\.(py)$", QRegularExpression::CaseInsensitiveOption));
582 patterns.push_back (QRegularExpression ("^.*\\.(r)$", QRegularExpression::CaseInsensitiveOption));
583 patterns.push_back (QRegularExpression ("^.*\\.(sd7)$", QRegularExpression::CaseInsensitiveOption));
584 patterns.push_back (QRegularExpression ("^.*\\.(tex|lyx)$", QRegularExpression::CaseInsensitiveOption));
585 patterns.push_back (QRegularExpression ("^.*\\.(vala)$", QRegularExpression::CaseInsensitiveOption));
586 patterns.push_back (QRegularExpression ("^.*\\.(v)$", QRegularExpression::CaseInsensitiveOption));
587 patterns.push_back (QRegularExpression ("^.*\\.(wiki)$", QRegularExpression::CaseInsensitiveOption));
588
589 #endif
590 }
591 */
592
check(const QString & fname) const593 bool CFTypeChecker::check (const QString &fname) const
594 {
595
596 #if QT_VERSION < 0x050000
597
598 for (size_t i = 0; i < patterns.size(); ++i)
599 {
600 if (patterns[i].exactMatch(fname))
601 return true;
602 }
603
604 #else
605
606 for (size_t i = 0; i < patterns.size(); ++i)
607 {
608 QRegularExpressionMatch match = patterns[i].match(fname);
609 if (match.hasMatch())
610 return true;
611 }
612
613 #endif
614
615 return false;
616 }
617
618
619 /*
620 GUI functions
621 */
622
623