1 /**
2 * @file src/megacmdcommonutils.cpp
3 * @brief MEGAcmd: Auxiliary methods
4 *
5 * (c) 2013 by Mega Limited, Auckland, New Zealand
6 *
7 * This file is part of the MEGAcmd.
8 *
9 * MEGAcmd is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * @copyright Simplified (2-clause) BSD License.
14 *
15 * You should have received a copy of the license along with this
16 * program.
17 */
18
19 #include "megacmdcommonutils.h"
20
21 #ifdef _WIN32
22 #include <Shlwapi.h> //PathAppend
23 #include <Shellapi.h> //CommandLineToArgvW
24 #else
25 #include <sys/ioctl.h> // console size
26 #include <unistd.h>
27 #endif
28
29 #include <iomanip>
30 #include <fstream>
31 #include <string.h>
32 #include <algorithm>
33 #include <sstream>
34 #include <limits.h>
35 #include <iterator>
36
37 #ifdef _WIN32
38 namespace mega {
39 //override for the log. This is required for compiling, otherwise SimpleLog won't compile.
operator <<(std::ostringstream & ostr,const std::wstring & str)40 std::ostringstream & operator<< ( std::ostringstream & ostr, const std::wstring & str)
41 {
42 std::string s;
43 megacmd::localwtostring(&str,&s);
44 ostr << s;
45 return ( ostr );
46 }
47 }
48 #endif
49
50 namespace megacmd {
51 using namespace std;
52
53 #ifdef _WIN32
operator <<(std::wostream & ostr,std::string const & str)54 std::wostream & operator<< ( std::wostream & ostr, std::string const & str )
55 {
56 std::wstring toout;
57 stringtolocalw(str.c_str(),&toout);
58 ostr << toout;
59 return ( ostr );
60 }
61
operator <<(std::wostream & ostr,const char * str)62 std::wostream & operator<< ( std::wostream & ostr, const char * str )
63 {
64 std::wstring toout;
65 stringtolocalw(str,&toout);
66 ostr << toout;
67 return ( ostr );
68 }
69
70 // convert UTF-8 to Windows Unicode wstring
stringtolocalw(const char * path,std::wstring * local)71 void stringtolocalw(const char* path, std::wstring* local)
72 {
73 // make space for the worst case
74 local->resize((strlen(path) + 1) * sizeof(wchar_t));
75
76 int wchars_num = MultiByteToWideChar(CP_UTF8, 0, path,-1, NULL,0);
77 local->resize(wchars_num);
78
79 int len = MultiByteToWideChar(CP_UTF8, 0, path,-1, (wchar_t*)local->data(), wchars_num);
80
81 if (len)
82 {
83 local->resize(len-1);
84 }
85 else
86 {
87 local->clear();
88 }
89 }
90
91 //widechar to utf8 string
localwtostring(const std::wstring * wide,std::string * multibyte)92 void localwtostring(const std::wstring* wide, std::string *multibyte)
93 {
94 if( !wide->empty() )
95 {
96 int size_needed = WideCharToMultiByte(CP_UTF8, 0, wide->data(), (int)wide->size(), NULL, 0, NULL, NULL);
97 multibyte->resize(size_needed);
98 WideCharToMultiByte(CP_UTF8, 0, wide->data(), (int)wide->size(), (char*)multibyte->data(), size_needed, NULL, NULL);
99 }
100 }
101
102 // convert Windows Unicode to UTF-8
utf16ToUtf8(const wchar_t * utf16data,int utf16size,string * utf8string)103 void utf16ToUtf8(const wchar_t* utf16data, int utf16size, string* utf8string)
104 {
105 if(!utf16size)
106 {
107 utf8string->clear();
108 return;
109 }
110
111 utf8string->resize((utf16size + 1) * 4);
112
113 utf8string->resize(WideCharToMultiByte(CP_UTF8, 0, utf16data,
114 utf16size,
115 (char*)utf8string->data(),
116 int(utf8string->size() + 1),
117 NULL, NULL));
118 }
119
getutf8fromUtf16(const wchar_t * ws)120 std::string getutf8fromUtf16(const wchar_t *ws)
121 {
122 string utf8s;
123 utf16ToUtf8(ws, wcslen(ws), &utf8s);
124 return utf8s;
125 }
126
127 #endif
128
129
canWrite(string path)130 bool canWrite(string path)
131 {
132 #ifdef _WIN32
133 // TODO: Check permissions
134 return true;
135 #else
136 if (access(path.c_str(), W_OK) == 0)
137 {
138 return true;
139 }
140 return false;
141 #endif
142 }
143
isPublicLink(string link)144 bool isPublicLink(string link)
145 {
146 //Old format:
147 //https://mega.nz/#!ph!key
148 //https://mega.nz/#F!ph!key
149
150 //new format:
151 //https://mega.nz/file/ph#key
152 //https://mega.nz/folder/ph#key
153 if (( link.find("http") == 0 ) && ( link.find("#") != string::npos || link.find("/file/") != string::npos || link.find("/folder/") != string::npos))
154 {
155 return true;
156 }
157 return false;
158 }
159
isEncryptedLink(string link)160 bool isEncryptedLink(string link)
161 {
162 if (( link.find("http") == 0 ) && ( link.find("#") != string::npos ) && (link.substr(link.find("#"),3) == "#P!") )
163 {
164 return true;
165 }
166 return false;
167 }
168
getPublicLinkHandle(const string & link)169 string getPublicLinkHandle(const string &link)
170 {
171 size_t posFolder = string::npos;
172 size_t posLastSep = link.rfind("?");
173 if (posLastSep == string::npos )
174 {
175 string rest = link;
176 int count = 0;
177 size_t posExc = rest.find_first_of("!");
178 while ( posExc != string::npos && (posExc +1) < rest.size())
179 {
180 count++;
181 if (count <= 3 )
182 {
183 posLastSep += posExc + 1;
184 }
185
186 rest = rest.substr(posExc + 1);
187 posExc = rest.find("!");
188 }
189
190 if (count != 3)
191 {
192 posLastSep = string::npos;
193 }
194 }
195
196 if (posLastSep == string::npos )
197 {
198 posFolder = link.find("/folder/");
199 }
200
201 if (posFolder != string::npos)
202 {
203 posLastSep = link.rfind("/file/");
204 if (posLastSep != string::npos)
205 {
206 posLastSep += strlen("/file/")-1;
207 }
208 else
209 {
210 posLastSep = link.rfind("/folder/");
211 if (posLastSep != string::npos && posFolder != posLastSep)
212 {
213 posLastSep += strlen("/folder/")-1;
214 }
215 else
216 {
217 return string();
218 }
219 }
220 }
221
222 if (( posLastSep == string::npos ) || !( posLastSep + 1 < link.length()))
223 {
224 return string();
225 }
226 else
227 {
228 return link.substr(posLastSep+1);
229 }
230 }
231
hasWildCards(string & what)232 bool hasWildCards(string &what)
233 {
234 return what.find('*') != string::npos || what.find('?') != string::npos;
235 }
236
charstoll(const char * instr)237 long long charstoll(const char *instr)
238 {
239 long long retval;
240
241 retval = 0;
242 for (; *instr; instr++) {
243 retval = 10*retval + (*instr - '0');
244 }
245 return retval;
246 }
247
ltrim(std::string & s,const char & c)248 std::string <rim(std::string &s, const char &c)
249 {
250 size_t pos = s.find_first_not_of(c);
251 s = s.substr(pos == string::npos ? s.length() : pos, s.length());
252 return s;
253 }
254
rtrim(std::string & s,const char & c)255 std::string &rtrim(std::string &s, const char &c)
256 {
257 size_t pos = s.find_last_of(c);
258 size_t last = pos == string::npos ? s.length() : pos;
259 if (last + 1 < s.length())
260 {
261 if (s.at(last + 1) != c)
262 {
263 last = s.length();
264 }
265 }
266
267 s = s.substr(0, last);
268 return s;
269 }
270
removeTrailingSeparators(string & path)271 string removeTrailingSeparators(string &path)
272 {
273 return rtrim(rtrim(path,'/'),'\\');
274 }
275
getlistOfWords(char * ptr,bool escapeBackSlashInCompletion,bool ignoreTrailingSpaces)276 vector<string> getlistOfWords(char *ptr, bool escapeBackSlashInCompletion, bool ignoreTrailingSpaces)
277 {
278 vector<string> words;
279
280 char* wptr;
281
282 // split line into words with quoting and escaping
283 for (;; )
284 {
285 // skip leading blank space
286 while (*(const signed char*)ptr > 0 && *ptr <= ' ' && (ignoreTrailingSpaces || *(ptr+1)))
287 {
288 ptr++;
289 }
290
291 if (!*ptr)
292 {
293 break;
294 }
295
296 // quoted arg / regular arg
297 if (*ptr == '"')
298 {
299 ptr++;
300 wptr = ptr;
301 words.push_back(string());
302
303 for (;; )
304 {
305 if (( *ptr == '"' ) || ( *ptr == '\\' ) || !*ptr)
306 {
307 words[words.size() - 1].append(wptr, ptr - wptr);
308
309 if (!*ptr || ( *ptr++ == '"' ))
310 {
311 break;
312 }
313
314 wptr = ptr - 1;
315 }
316 else
317 {
318 ptr++;
319 }
320 }
321 }
322 else if (*ptr == '\'') // quoted arg / regular arg
323 {
324 ptr++;
325 wptr = ptr;
326 words.push_back(string());
327
328 for (;; )
329 {
330 if (( *ptr == '\'' ) || ( *ptr == '\\' ) || !*ptr)
331 {
332 words[words.size() - 1].append(wptr, ptr - wptr);
333
334 if (!*ptr || ( *ptr++ == '\'' ))
335 {
336 break;
337 }
338
339 wptr = ptr - 1;
340 }
341 else
342 {
343 ptr++;
344 }
345 }
346 }
347 else
348 {
349 while (*ptr == ' ') ptr++;// only possible if ptr+1 is the end
350
351 wptr = ptr;
352
353 char *prev = ptr;
354 //while ((unsigned char)*ptr > ' ')
355 while ((*ptr != '\0') && !(*ptr ==' ' && *prev !='\\'))
356 {
357 if (*ptr == '"')
358 {
359 while (*++ptr != '"' && *ptr != '\0')
360 { }
361 }
362 prev=ptr;
363 ptr++;
364 }
365 string newword(wptr, ptr - wptr);
366 words.push_back(newword);
367 }
368 }
369
370 if (escapeBackSlashInCompletion && words.size()> 1 && words[0] == "completion")
371 {
372 for (int i = 1; i < (int)words.size(); i++)
373 {
374 replaceAll(words[i],"\\","\\\\");
375 }
376 }
377
378 return words;
379 }
380
stringcontained(const char * s,vector<string> list)381 bool stringcontained(const char * s, vector<string> list)
382 {
383 for (int i = 0; i < (int)list.size(); i++)
384 {
385 if (list[i] == s)
386 {
387 return true;
388 }
389 }
390
391 return false;
392 }
393
dupstr(char * s)394 char * dupstr(char* s)
395 {
396 char *r;
397
398 r = (char*)malloc(sizeof( char ) * ( strlen(s) + 1 ));
399 strcpy(r, s);
400 return( r );
401 }
402
replace(std::string & str,const std::string & from,const std::string & to)403 bool replace(std::string& str, const std::string& from, const std::string& to)
404 {
405 size_t start_pos = str.find(from);
406 if (start_pos == std::string::npos)
407 {
408 return false;
409 }
410 str.replace(start_pos, from.length(), to);
411 return true;
412 }
413
replaceAll(std::string & str,const std::string & from,const std::string & to)414 void replaceAll(std::string& str, const std::string& from, const std::string& to)
415 {
416 if (from.empty())
417 {
418 return;
419 }
420 size_t start_pos = 0;
421 while (( start_pos = str.find(from, start_pos)) != std::string::npos)
422 {
423 str.replace(start_pos, from.length(), to);
424 start_pos += to.length();
425 }
426 }
427
toInteger(string what,int failValue)428 int toInteger(string what, int failValue)
429 {
430 if (what.empty())
431 {
432 return failValue;
433 }
434 if (!isdigit(what[0]) && !( what[0] != '-' ) && ( what[0] != '+' ))
435 {
436 return failValue;
437 }
438
439 char * p;
440 long l = strtol(what.c_str(), &p, 10);
441
442 if (*p != 0)
443 {
444 return failValue;
445 }
446
447 if (( l < INT_MIN ) || ( l > INT_MAX ))
448 {
449 return failValue;
450 }
451 return (int)l;
452 }
453
joinStrings(const vector<string> & vec,const char * delim,bool quoted)454 string joinStrings(const vector<string>& vec, const char* delim, bool quoted)
455 {
456 stringstream res;
457 if (!quoted)
458 {
459 std:copy(vec.begin(), vec.end(), ostream_iterator<string>(res, delim));
460 }
461 else
462 {
463 for(vector<string>::const_iterator i = vec.begin(); i != vec.end(); ++i)
464 {
465 res << "\"" << *i << "\"" << delim;
466 }
467 }
468 if (vec.size()>1)
469 {
470 string toret = res.str();
471 return toret.substr(0,toret.size()-strlen(delim));
472 }
473 return res.str();
474 }
475
getstringutf8size(const string & str)476 unsigned int getstringutf8size(const string &str) {
477 int c,i,ix,q;
478 for (q=0, i=0, ix=int(str.length()); i < ix; i++, q++)
479 {
480 c = (unsigned char) str[i];
481
482 if (c>=0 && c<=127) i+=0;
483 else if ((c & 0xE0) == 0xC0) i+=1;
484 #ifdef _WIN32
485 else if ((c & 0xF0) == 0xE0) i+=2;
486 #else
487 else if ((c & 0xF0) == 0xE0)
488 {
489 if ((i+2)>ix || c != 0xE2 || (strncmp(&str.c_str()[i],"\u21f5",3)
490 && strncmp(&str.c_str()[i],"\u21d3",3) && strncmp(&str.c_str()[i],"\u21d1",3) ) )
491 { //known 1 character gliphs
492 q++;
493 }
494 i+=2;
495 } //these gliphs may occupy 2 characters! Problem: not always. Let's assume the worse
496 #endif
497 else if ((c & 0xF8) == 0xF0) i+=3;
498 else return 0;//invalid utf8
499 }
500 return q;
501 }
502
getFixLengthString(const string & origin,unsigned int size,const char delim,bool alignedright)503 string getFixLengthString(const string &origin, unsigned int size, const char delim, bool alignedright)
504 {
505 string toret;
506 size_t printableSize = getstringutf8size(origin);
507 size_t bytesSize = origin.size();
508 if (printableSize <= size){
509 if (alignedright)
510 {
511 toret.insert(0,size-printableSize,delim);
512 toret.insert(size-bytesSize,origin,0,bytesSize);
513
514 }
515 else
516 {
517 toret.insert(0,origin,0,bytesSize);
518 toret.insert(bytesSize,size-printableSize,delim);
519 }
520 }
521 else
522 {
523 toret.insert(0,origin,0,(size+1)/2-2);
524 if (size > 3) toret.insert((size+1)/2-2,3,'.');
525 if (size > 1) toret.insert((size+1)/2+1,origin,bytesSize-(size)/2+1,(size)/2-1); //TODO: This could break characters if multibyte! //alternative: separate in multibyte strings and print one by one?
526 }
527
528 return toret;
529 }
530
getRightAlignedString(const string origin,unsigned int minsize)531 string getRightAlignedString(const string origin, unsigned int minsize)
532 {
533 ostringstream os;
534 os << std::setw(minsize) << origin;
535 return os.str();
536 }
537
printCenteredLine(OUTSTREAMTYPE & os,string msj,unsigned int width,bool encapsulated)538 void printCenteredLine(OUTSTREAMTYPE &os, string msj, unsigned int width, bool encapsulated)
539 {
540 unsigned int msjsize = getstringutf8size(msj);
541 bool overflowed = false;
542 if (msjsize>width)
543 {
544 overflowed = true;
545 width = unsigned(msjsize);
546 }
547 if (encapsulated && !overflowed)
548 os << "|";
549 for (unsigned int i = 0; i < (width-msjsize)/2; i++)
550 os << " ";
551 os << msj;
552 for (unsigned int i = 0; i < (width-msjsize)/2 + (width-msjsize)%2 ; i++)
553 os << " ";
554 if (encapsulated && !overflowed)
555 os << "|";
556 os << endl;
557 }
558
printCenteredContents(OUTSTREAMTYPE & os,string msj,unsigned int width,bool encapsulated)559 void printCenteredContents(OUTSTREAMTYPE &os, string msj, unsigned int width, bool encapsulated)
560 {
561 string headfoot = " ";
562 headfoot.append(width, '-');
563 unsigned int msjsize = getstringutf8size(msj);
564
565 bool printfooter = false;
566
567 if (msj.size())
568 {
569 string header;
570 if (msj.at(0) == '<')
571 {
572 size_t possenditle = msj.find(">");
573 if (width >= 2 && possenditle < (width -2))
574 {
575 header.append(" ");
576 header.append((width - possenditle ) / 2, '-');
577 header.append(msj.substr(0,possenditle+1));
578 header.append(width - getstringutf8size(header) + 1, '-');
579 msj = msj.substr(possenditle + 1);
580 }
581 }
582 if (header.size() || encapsulated)
583 {
584 os << (header.size()?header:headfoot) << endl;
585 printfooter = true;
586 }
587 }
588
589 size_t possepnewline = msj.find("\n");
590 size_t possep = msj.find(" ");
591
592 if (possepnewline != string::npos && possepnewline < width)
593 {
594 possep = possepnewline;
595 }
596 size_t possepprev = possep;
597
598
599 while (msj.size())
600 {
601
602 if (possepnewline != string::npos && possepnewline <= width)
603 {
604 possep = possepnewline;
605 possepprev = possep;
606 }
607 else
608 {
609 while (possep < width && possep != string::npos)
610 {
611 possepprev = possep;
612 possep = msj.find_first_of(" ", possep+1);
613 }
614 }
615
616 if (possepprev == string::npos || (possep == string::npos && msj.size() <= width))
617 {
618 printCenteredLine(os, msj, width, encapsulated);
619 break;
620 }
621 else
622 {
623 printCenteredLine(os, msj.substr(0,possepprev), width, encapsulated);
624 if (possepprev < (msj.size() - 1))
625 {
626 msj = msj.substr(possepprev + 1);
627 possepnewline = msj.find("\n");
628 possep = msj.find(" ");
629 possepprev = possep;
630 }
631 else
632 {
633 break;
634 }
635 }
636 }
637 if (printfooter)
638 {
639 os << headfoot << endl;
640 }
641 }
642
printCenteredLine(string msj,unsigned int width,bool encapsulated)643 void printCenteredLine(string msj, unsigned int width, bool encapsulated)
644 {
645 OUTSTRINGSTREAM os;
646 printCenteredLine(os, msj, width, encapsulated);
647 COUT << os.str();
648 }
649
printCenteredContents(string msj,unsigned int width,bool encapsulated)650 void printCenteredContents(string msj, unsigned int width, bool encapsulated)
651 {
652 OUTSTRINGSTREAM os;
653 printCenteredContents(os, msj, width, encapsulated);
654 COUT << os.str();
655 }
656
printCenteredContentsCerr(string msj,unsigned int width,bool encapsulated)657 void printCenteredContentsCerr(string msj, unsigned int width, bool encapsulated)
658 {
659 OUTSTRINGSTREAM os;
660 printCenteredContents(os, msj, width, encapsulated);
661 CERR << os.str();
662 }
663
printPercentageLineCerr(const char * title,long long completed,long long total,float percentDowloaded,bool cleanLineAfter)664 void printPercentageLineCerr(const char *title, long long completed, long long total, float percentDowloaded, bool cleanLineAfter)
665 {
666 int cols = getNumberOfCols(80);
667
668 string outputString;
669 outputString.resize(cols + 1);
670 for (int i = 0; i < cols; i++)
671 {
672 outputString[i] = '.';
673 }
674
675 outputString[cols] = '\0';
676 char *ptr = (char *)outputString.c_str();
677 sprintf(ptr, "%s%s", title, " ||");
678 ptr += strlen(title);
679 ptr += strlen(" ||");
680 *ptr = '.'; //replace \0 char
681
682 char aux[41];
683
684 if (total < 1048576)
685 {
686 sprintf(aux,"||(%lld/%lld KB: %6.2f %%) ", completed / 1024, total / 1024, percentDowloaded);
687 }
688 else
689 {
690 sprintf(aux,"||(%lld/%lld MB: %6.2f %%) ", completed / 1024 / 1024, total / 1024 / 1024, percentDowloaded);
691 }
692
693
694 sprintf((char *)outputString.c_str() + cols - strlen(aux), "%s", aux);
695 for (int i = 0; i < ( cols - (strlen(title) + strlen(" ||")) - strlen(aux)) * 1.0 * min(100.0f,percentDowloaded) / 100.0; i++)
696 {
697 *ptr++ = '#';
698 }
699
700 if (cleanLineAfter)
701 {
702 cerr << outputString << '\r' << flush;
703 }
704 else
705 {
706 cerr << outputString << endl;
707 }
708 }
709
getFlag(map<string,int> * flags,const char * optname)710 int getFlag(map<string, int> *flags, const char * optname)
711 {
712 return flags->count(optname) ? ( *flags )[optname] : 0;
713 }
714
getOption(map<string,string> * cloptions,const char * optname,string defaultValue)715 string getOption(map<string, string> *cloptions, const char * optname, string defaultValue)
716 {
717 return cloptions->count(optname) ? ( *cloptions )[optname] : defaultValue;
718 }
719
getintOption(map<string,string> * cloptions,const char * optname,int defaultValue)720 int getintOption(map<string, string> *cloptions, const char * optname, int defaultValue)
721 {
722 if (cloptions->count(optname))
723 {
724 int i = defaultValue;
725 istringstream is(( *cloptions )[optname]);
726 is >> i;
727 return i;
728 }
729 else
730 {
731 return defaultValue;
732 }
733 }
734
discardOptionsAndFlags(vector<string> * ws)735 void discardOptionsAndFlags(vector<string> *ws)
736 {
737 for (std::vector<string>::iterator it = ws->begin(); it != ws->end(); )
738 {
739 /* std::cout << *it; ... */
740 string w = ( string ) * it;
741 if (w.length() && ( w.at(0) == '-' )) //begins with "-"
742 {
743 it = ws->erase(it);
744 }
745 else //not an option/flag
746 {
747 ++it;
748 }
749 }
750 }
751
sizeProgressToText(long long partialSize,long long totalSize,bool equalizeUnitsLength,bool humanreadable)752 string sizeProgressToText(long long partialSize, long long totalSize, bool equalizeUnitsLength, bool humanreadable)
753 {
754 ostringstream os;
755 os.precision(2);
756 if (humanreadable)
757 {
758 string unit;
759 unit = ( equalizeUnitsLength ? " B" : "B" );
760 double reducedPartSize = (double)totalSize;
761 double reducedSize = (double)totalSize;
762
763 if ( totalSize > 1099511627776LL *2 )
764 {
765 reducedPartSize = totalSize / (double) 1099511627776ull;
766 reducedSize = totalSize / (double) 1099511627776ull;
767 unit = "TB";
768 }
769 else if ( totalSize > 1073741824LL *2 )
770 {
771 reducedPartSize = totalSize / (double) 1073741824L;
772 reducedSize = totalSize / (double) 1073741824L;
773 unit = "GB";
774 }
775 else if (totalSize > 1048576 * 2)
776 {
777 reducedPartSize = totalSize / (double) 1048576;
778 reducedSize = totalSize / (double) 1048576;
779 unit = "MB";
780 }
781 else if (totalSize > 1024 * 2)
782 {
783 reducedPartSize = totalSize / (double) 1024;
784 reducedSize = totalSize / (double) 1024;
785 unit = "KB";
786 }
787 os << fixed << reducedPartSize << "/" << reducedSize;
788 os << " " << unit;
789 }
790 else
791 {
792 os << partialSize << "/" << totalSize;
793 }
794
795 return os.str();
796 }
797
sizeToText(long long totalSize,bool equalizeUnitsLength,bool humanreadable)798 string sizeToText(long long totalSize, bool equalizeUnitsLength, bool humanreadable)
799 {
800 ostringstream os;
801 os.precision(2);
802 if (humanreadable)
803 {
804 string unit;
805 unit = ( equalizeUnitsLength ? " B" : "B" );
806 double reducedSize = (double)totalSize;
807
808 if ( totalSize > 1099511627776LL *2 )
809 {
810 reducedSize = totalSize / (double) 1099511627776ull;
811 unit = "TB";
812 }
813 else if ( totalSize > 1073741824LL *2 )
814 {
815 reducedSize = totalSize / (double) 1073741824L;
816 unit = "GB";
817 }
818 else if (totalSize > 1048576 * 2)
819 {
820 reducedSize = totalSize / (double) 1048576;
821 unit = "MB";
822 }
823 else if (totalSize > 1024 * 2)
824 {
825 reducedSize = totalSize / (double) 1024;
826 unit = "KB";
827 }
828 os << fixed << reducedSize;
829 os << " " << unit;
830 }
831 else
832 {
833 os << totalSize;
834 }
835
836 return os.str();
837 }
838
textToSize(const char * text)839 int64_t textToSize(const char *text)
840 {
841 int64_t sizeinbytes = 0;
842
843 char * ptr = (char *)text;
844 char * last = (char *)text;
845 while (*ptr != '\0')
846 {
847 if (( *ptr < '0' ) || ( *ptr > '9' ) || ( *ptr == '.' ) )
848 {
849 switch (*ptr)
850 {
851 case 'b': //Bytes
852 case 'B':
853 *ptr = '\0';
854 sizeinbytes += int64_t(atof(last));
855 break;
856
857 case 'k': //KiloBytes
858 case 'K':
859 *ptr = '\0';
860 sizeinbytes += int64_t(1024.0 * atof(last));
861 break;
862
863 case 'm': //MegaBytes
864 case 'M':
865 *ptr = '\0';
866 sizeinbytes += int64_t(1048576.0 * atof(last));
867 break;
868
869 case 'g': //GigaBytes
870 case 'G':
871 *ptr = '\0';
872 sizeinbytes += int64_t(1073741824.0 * atof(last));
873 break;
874
875 case 't': //TeraBytes
876 case 'T':
877 *ptr = '\0';
878 sizeinbytes += int64_t(1125899906842624.0 * atof(last));
879 break;
880
881 default:
882 {
883 return -1;
884 }
885 }
886 last = ptr + 1;
887 }
888 char *prev = ptr;
889 ptr++;
890 if (*ptr == '\0' && ( ( *prev == '.' ) || ( ( *prev >= '0' ) && ( *prev <= '9' ) ) ) ) //reach the end with a number or dot
891 {
892 return -1;
893 }
894 }
895 return sizeinbytes;
896
897 }
898
percentageToText(float percentage)899 string percentageToText(float percentage)
900 {
901 ostringstream os;
902 os.precision(2);
903 if (percentage != percentage) //NaN
904 {
905 os << "----%";
906 }
907 else
908 {
909 os << fixed << percentage*100.0 << "%";
910 }
911
912 return os.str();
913 }
914
getNumberOfCols(unsigned int defaultwidth)915 unsigned int getNumberOfCols(unsigned int defaultwidth)
916 {
917 #ifdef _WIN32
918 CONSOLE_SCREEN_BUFFER_INFO csbi;
919 int columns = defaultwidth;
920
921 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
922 {
923 columns = csbi.srWindow.Right - csbi.srWindow.Left - 1;
924 }
925
926 return columns;
927 #else
928 struct winsize size;
929 if ( ioctl(STDOUT_FILENO,TIOCGWINSZ,&size) != -1
930 || (ioctl(STDIN_FILENO,TIOCGWINSZ,&size) != -1))
931 {
932 if (size.ws_col > 2)
933 {
934 return size.ws_col - 2;
935 }
936 }
937 #endif
938 return defaultwidth;
939 }
940
sleepSeconds(int seconds)941 void sleepSeconds(int seconds)
942 {
943 #ifdef _WIN32
944 Sleep(1000*seconds);
945 #else
946 sleep(seconds);
947 #endif
948 }
949
sleepMilliSeconds(long milliseconds)950 void sleepMilliSeconds(long milliseconds)
951 {
952 #ifdef _WIN32
953 Sleep(milliseconds);
954 #else
955 usleep(milliseconds *1000);
956 #endif
957 }
958
isValidEmail(string email)959 bool isValidEmail(string email)
960 {
961 return !( (email.find("@") == string::npos)
962 || (email.find_last_of(".") == string::npos)
963 || (email.find("@") > email.find_last_of(".")));
964 }
965
966 #ifdef __linux__
getCurrentExecPath()967 std::string getCurrentExecPath()
968 {
969 std::string path = ".";
970 pid_t pid = getpid();
971 char buf[20] = {0};
972 sprintf(buf,"%d",pid);
973 std::string _link = "/proc/";
974 _link.append( buf );
975 _link.append( "/exe");
976 char proc[PATH_MAX];
977 int ch = readlink(_link.c_str(),proc,PATH_MAX);
978 if (ch != -1) {
979 proc[ch] = 0;
980 path = proc;
981 std::string::size_type t = path.find_last_of("/");
982 path = path.substr(0,t);
983 }
984
985 return path;
986 }
987 #endif
988
ltrimProperty(string & s,const char & c)989 string <rimProperty(string &s, const char &c)
990 {
991 size_t pos = s.find_first_not_of(c);
992 s = s.substr(pos == string::npos ? s.length() : pos, s.length());
993 return s;
994 }
995
rtrimProperty(string & s,const char & c)996 string &rtrimProperty(string &s, const char &c)
997 {
998 size_t pos = s.find_last_not_of(c);
999 if (pos != string::npos)
1000 {
1001 pos++;
1002 }
1003 s = s.substr(0, pos);
1004 return s;
1005 }
1006
trimProperty(string & what)1007 string &trimProperty(string &what)
1008 {
1009 rtrimProperty(what,' ');
1010 ltrimProperty(what,' ');
1011 if (what.size() > 1)
1012 {
1013 if (what[0] == '\'' || what[0] == '"')
1014 {
1015 rtrimProperty(what, what[0]);
1016 ltrimProperty(what, what[0]);
1017 }
1018 }
1019 return what;
1020 }
1021
getPropertyFromFile(const char * configFile,const char * propertyName)1022 string getPropertyFromFile(const char *configFile, const char *propertyName)
1023 {
1024 ifstream infile(configFile);
1025 string line;
1026
1027 while (getline(infile, line))
1028 {
1029 if (line.length() > 0 && line[0] != '#')
1030 {
1031 if (!strlen(propertyName)) //if empty return first line
1032 {
1033 return trimProperty(line);
1034 }
1035 string key, value;
1036 size_t pos = line.find("=");
1037 if (pos != string::npos && ((pos + 1) < line.size()))
1038 {
1039 key = line.substr(0, pos);
1040 rtrimProperty(key, ' ');
1041
1042 if (!strcmp(key.c_str(), propertyName))
1043 {
1044 value = line.substr(pos + 1);
1045 return trimProperty(value);
1046 }
1047 }
1048 }
1049 }
1050
1051 return string();
1052 }
1053
endregistry()1054 void ColumnDisplayer::endregistry()
1055 {
1056 values.push_back(std::move(currentRegistry));
1057 currentlength = 0;
1058 }
1059
addHeader(const string & name,bool fixed,int minWidth)1060 void ColumnDisplayer::addHeader(const string &name, bool fixed, int minWidth)
1061 {
1062 fields[name] = Field(name, fixed, minWidth);
1063 }
1064
addValue(const string & name,const string & value,bool replace)1065 void ColumnDisplayer::addValue(const string &name, const string &value, bool replace)
1066 {
1067 int len = getstringutf8size(value);
1068 if (!replace)
1069 {
1070 if (currentRegistry.size() && currentRegistry.find(name) != currentRegistry.end())
1071 {
1072 endregistry();
1073 }
1074 }
1075
1076 currentRegistry[name] = value;
1077 currentlength += len;
1078 if (fields.find(name) == fields.end())
1079 {
1080 addHeader(name, true);
1081 }
1082 if (find (fieldnames.begin(), fieldnames.end(), name) == fieldnames.end())
1083 {
1084 fieldnames.push_back(name);
1085 }
1086
1087 fields[name].updateMaxValue(len);
1088 }
1089
ColumnDisplayer(int unfixedColsMinSize)1090 ColumnDisplayer::ColumnDisplayer(int unfixedColsMinSize) : mUnfixedColsMinSize(unfixedColsMinSize)
1091 {
1092
1093 }
1094
print(OUTSTREAMTYPE & os,int fullWidth,bool printHeader)1095 void ColumnDisplayer::print(OUTSTREAMTYPE &os, int fullWidth, bool printHeader)
1096 {
1097 if (currentRegistry.size())
1098 {
1099 endregistry();
1100 }
1101
1102 int unfixedfieldscount = 0;
1103 int unfixedFieldsMaxLengthSum = 0;
1104
1105 int leftWidth = fullWidth;
1106 vector<Field *> unfixedfields;
1107 for (auto &el : fields)
1108 {
1109 Field &f = el.second;
1110 if (f.fixedSize)
1111
1112 {
1113 if (f.fixedWidth)
1114 {
1115 f.dispWidth = f.fixedWidth;
1116 }
1117 else
1118 {
1119 f.dispWidth = max((int)getstringutf8size(f.name),f.maxValueLength);
1120 }
1121 leftWidth-=(f.dispWidth + 1);
1122 }
1123 else
1124 {
1125 unfixedfieldscount++;
1126 unfixedfields.push_back(&f);
1127 unfixedFieldsMaxLengthSum+=f.maxValueLength;
1128 }
1129 }
1130
1131 auto unfixedFieldsMaxLengthsLeft = unfixedFieldsMaxLengthSum;
1132 for (auto &f: unfixedfields)
1133 {
1134 unfixedFieldsMaxLengthsLeft -= f->maxValueLength;
1135
1136 f->dispWidth = max(
1137 (int)getstringutf8size(f->name), // min limit: header size
1138 min( f->maxValueLength // max limit: its longest value
1139 , max(mUnfixedColsMinSize, // min limit 2: the min limit for unfixed columns
1140 max((leftWidth - unfixedfieldscount + 1)/(unfixedfieldscount), (leftWidth - unfixedfieldscount + 1 - unfixedFieldsMaxLengthsLeft)) //either an equitative share between all unfixedfields left, or all the space the other left me considering their maxLegnths
1141 )
1142 )
1143 );
1144 leftWidth-=(f->dispWidth + 1);
1145 unfixedfieldscount--;
1146 }
1147
1148 if (printHeader)
1149 {
1150 bool first = true;
1151 for (auto el : fieldnames)
1152 {
1153 Field &f = fields[el];
1154 if (!first)
1155 {
1156 os << " ";
1157 }
1158 first = false;
1159 os << getFixLengthString(f.name, f.dispWidth);
1160 }
1161 }
1162 os << std::endl;
1163
1164 for (auto ®istry : values)
1165 {
1166 bool firstvalue = true;
1167 for (auto &el : fieldnames)
1168 {
1169 Field &f = fields[el];
1170 if (!firstvalue)
1171 {
1172 os << " ";
1173 }
1174 firstvalue = false;
1175
1176 if (registry.find(f.name) != registry.end())
1177 {
1178 os << getFixLengthString(registry[f.name], f.dispWidth);
1179 }
1180 else
1181 {
1182 os << getFixLengthString("", f.dispWidth);
1183 }
1184
1185 }
1186 os << std::endl;
1187 }
1188 }
1189
Field()1190 Field::Field()
1191 {
1192
1193 }
1194
Field(string name,bool fixed,int minWidth)1195 Field::Field(string name, bool fixed, int minWidth) :name(name), fixedSize(fixed), fixedWidth(minWidth)
1196 {
1197 if (fixed)
1198 {
1199 this->dispWidth = minWidth;
1200 }
1201
1202 }
1203
updateMaxValue(int newcandidate)1204 void Field::updateMaxValue(int newcandidate)
1205 {
1206 if (newcandidate > this->maxValueLength)
1207 {
1208 this->maxValueLength = newcandidate;
1209 }
1210 }
1211
1212 } //end namespace
1213