• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2017-2020 Advanced Micro Devices, Inc. All rights reserved.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #include "Common.h"
24 
StrRangeToPtrList(const StrRange & s,std::vector<uint64_t> & out)25 bool StrRangeToPtrList(const StrRange& s, std::vector<uint64_t>& out)
26 {
27     out.clear();
28     StrRange currRange = { s.beg, nullptr };
29     while(currRange.beg < s.end)
30     {
31         currRange.end = currRange.beg;
32         while(currRange.end < s.end && *currRange.end != ' ')
33         {
34             ++currRange.end;
35         }
36 
37         uint64_t ptr = 0;
38         if(!StrRangeToPtr(currRange, ptr))
39         {
40             return false;
41         }
42         out.push_back(ptr);
43 
44         currRange.beg = currRange.end + 1;
45     }
46     return true;
47 }
48 
49 ////////////////////////////////////////////////////////////////////////////////
50 // LineSplit class
51 
GetNextLine(StrRange & out)52 bool LineSplit::GetNextLine(StrRange& out)
53 {
54     if(m_NextLineBeg < m_NumBytes)
55     {
56         out.beg = m_Data + m_NextLineBeg;
57         size_t currLineEnd = m_NextLineBeg;
58         while(currLineEnd < m_NumBytes && m_Data[currLineEnd] != '\n')
59             ++currLineEnd;
60         out.end = m_Data + currLineEnd;
61         // Ignore trailing '\r' to support Windows end of line.
62         if(out.end > out.beg && *(out.end - 1) == '\r')
63         {
64             --out.end;
65         }
66         m_NextLineBeg = currLineEnd + 1; // Past '\n'
67         ++m_NextLineIndex;
68         return true;
69     }
70     else
71         return false;
72 }
73 
74 ////////////////////////////////////////////////////////////////////////////////
75 // CsvSplit class
76 
Set(const StrRange & line,size_t maxCount)77 void CsvSplit::Set(const StrRange& line, size_t maxCount)
78 {
79     assert(maxCount <= RANGE_COUNT_MAX);
80     m_Line = line;
81     const size_t strLen = line.length();
82     size_t rangeIndex = 0;
83     size_t charIndex = 0;
84     while(charIndex < strLen && rangeIndex < maxCount)
85     {
86         m_Ranges[rangeIndex * 2] = charIndex;
87         while(charIndex < strLen && (rangeIndex + 1 == maxCount || m_Line.beg[charIndex] != ','))
88             ++charIndex;
89         m_Ranges[rangeIndex * 2 + 1] = charIndex;
90         ++rangeIndex;
91         ++charIndex; // Past ','
92     }
93     m_Count = rangeIndex;
94 }
95 
96 ////////////////////////////////////////////////////////////////////////////////
97 // class CmdLineParser
98 
ReadNextArg(std::string * OutArg)99 bool CmdLineParser::ReadNextArg(std::string *OutArg)
100 {
101 	if (m_argv != NULL)
102 	{
103 		if (m_ArgIndex >= (size_t)m_argc) return false;
104 
105 		*OutArg = m_argv[m_ArgIndex];
106 		m_ArgIndex++;
107 		return true;
108 	}
109 	else
110 	{
111 		if (m_ArgIndex >= m_CmdLineLength) return false;
112 
113 		OutArg->clear();
114 		bool InsideQuotes = false;
115 		while (m_ArgIndex < m_CmdLineLength)
116 		{
117 			char Ch = m_CmdLine[m_ArgIndex];
118 			if (Ch == '\\')
119 			{
120 				bool FollowedByQuote = false;
121 				size_t BackslashCount = 1;
122 				size_t TmpIndex = m_ArgIndex + 1;
123 				while (TmpIndex < m_CmdLineLength)
124 				{
125 					char TmpCh = m_CmdLine[TmpIndex];
126 					if (TmpCh == '\\')
127 					{
128 						BackslashCount++;
129 						TmpIndex++;
130 					}
131 					else if (TmpCh == '"')
132 					{
133 						FollowedByQuote = true;
134 						break;
135 					}
136 					else
137 						break;
138 				}
139 
140 				if (FollowedByQuote)
141 				{
142 					if (BackslashCount % 2 == 0)
143 					{
144 						for (size_t i = 0; i < BackslashCount / 2; i++)
145 							*OutArg += '\\';
146 						m_ArgIndex += BackslashCount + 1;
147 						InsideQuotes = !InsideQuotes;
148 					}
149 					else
150 					{
151 						for (size_t i = 0; i < BackslashCount / 2; i++)
152 							*OutArg += '\\';
153 						*OutArg += '"';
154 						m_ArgIndex += BackslashCount + 1;
155 					}
156 				}
157 				else
158 				{
159 					for (size_t i = 0; i < BackslashCount; i++)
160 						*OutArg += '\\';
161 					m_ArgIndex += BackslashCount;
162 				}
163 			}
164 			else if (Ch == '"')
165 			{
166 				InsideQuotes = !InsideQuotes;
167 				m_ArgIndex++;
168 			}
169 			else if (isspace(Ch))
170 			{
171 				if (InsideQuotes)
172 				{
173 					*OutArg += Ch;
174 					m_ArgIndex++;
175 				}
176 				else
177 				{
178 					m_ArgIndex++;
179 					break;
180 				}
181 			}
182 			else
183 			{
184 				*OutArg += Ch;
185 				m_ArgIndex++;
186 			}
187 		}
188 
189 		while (m_ArgIndex < m_CmdLineLength && isspace(m_CmdLine[m_ArgIndex]))
190 			m_ArgIndex++;
191 
192 		return true;
193 	}
194 }
195 
FindShortOpt(char Opt)196 CmdLineParser::SHORT_OPT * CmdLineParser::FindShortOpt(char Opt)
197 {
198 	for (size_t i = 0; i < m_ShortOpts.size(); i++)
199 		if (m_ShortOpts[i].Opt == Opt)
200 			return &m_ShortOpts[i];
201 	return NULL;
202 }
203 
FindLongOpt(const std::string & Opt)204 CmdLineParser::LONG_OPT * CmdLineParser::FindLongOpt(const std::string &Opt)
205 {
206 	for (size_t i = 0; i < m_LongOpts.size(); i++)
207 		if (m_LongOpts[i].Opt == Opt)
208 			return &m_LongOpts[i];
209 	return NULL;
210 }
211 
CmdLineParser(int argc,char ** argv)212 CmdLineParser::CmdLineParser(int argc, char **argv) :
213 	m_argv(argv),
214 	m_CmdLine(NULL),
215 	m_argc(argc),
216 	m_CmdLineLength(0),
217 	m_ArgIndex(1),
218 	m_InsideMultioption(false),
219 	m_LastArgIndex(0),
220 	m_LastOptId(0)
221 {
222 	assert(argc > 0);
223 	assert(argv != NULL);
224 }
225 
CmdLineParser(const char * CmdLine)226 CmdLineParser::CmdLineParser(const char *CmdLine) :
227 	m_argv(NULL),
228 	m_CmdLine(CmdLine),
229 	m_argc(0),
230 	m_ArgIndex(0),
231 	m_InsideMultioption(false),
232 	m_LastArgIndex(0),
233 	m_LastOptId(0)
234 {
235 	assert(CmdLine != NULL);
236 
237 	m_CmdLineLength = strlen(m_CmdLine);
238 
239 	while (m_ArgIndex < m_CmdLineLength && isspace(m_CmdLine[m_ArgIndex]))
240 		m_ArgIndex++;
241 }
242 
RegisterOpt(uint32_t Id,char Opt,bool Parameter)243 void CmdLineParser::RegisterOpt(uint32_t Id, char Opt, bool Parameter)
244 {
245 	assert(Opt != '\0');
246 
247 	m_ShortOpts.push_back(SHORT_OPT(Id, Opt, Parameter));
248 }
249 
RegisterOpt(uint32_t Id,const std::string & Opt,bool Parameter)250 void CmdLineParser::RegisterOpt(uint32_t Id, const std::string &Opt, bool Parameter)
251 {
252 	assert(!Opt.empty());
253 
254 	m_LongOpts.push_back(LONG_OPT(Id, Opt, Parameter));
255 }
256 
ReadNext()257 CmdLineParser::RESULT CmdLineParser::ReadNext()
258 {
259 	if (m_InsideMultioption)
260 	{
261 		assert(m_LastArgIndex < m_LastArg.length());
262 		SHORT_OPT *so = FindShortOpt(m_LastArg[m_LastArgIndex]);
263 		if (so == NULL)
264 		{
265 			m_LastOptId = 0;
266 			m_LastParameter.clear();
267 			return CmdLineParser::RESULT_ERROR;
268 		}
269 		if (so->Parameter)
270 		{
271 			if (m_LastArg.length() == m_LastArgIndex+1)
272 			{
273 				if (!ReadNextArg(&m_LastParameter))
274 				{
275 					m_LastOptId = 0;
276 					m_LastParameter.clear();
277 					return CmdLineParser::RESULT_ERROR;
278 				}
279 				m_InsideMultioption = false;
280 				m_LastOptId = so->Id;
281 				return CmdLineParser::RESULT_OPT;
282 			}
283 			else if (m_LastArg[m_LastArgIndex+1] == '=')
284 			{
285 				m_InsideMultioption = false;
286 				m_LastParameter = m_LastArg.substr(m_LastArgIndex+2);
287 				m_LastOptId = so->Id;
288 				return CmdLineParser::RESULT_OPT;
289 			}
290 			else
291 			{
292 				m_InsideMultioption = false;
293 				m_LastParameter = m_LastArg.substr(m_LastArgIndex+1);
294 				m_LastOptId = so->Id;
295 				return CmdLineParser::RESULT_OPT;
296 			}
297 		}
298 		else
299 		{
300 			if (m_LastArg.length() == m_LastArgIndex+1)
301 			{
302 				m_InsideMultioption = false;
303 				m_LastParameter.clear();
304 				m_LastOptId = so->Id;
305 				return CmdLineParser::RESULT_OPT;
306 			}
307 			else
308 			{
309 				m_LastArgIndex++;
310 
311 				m_LastParameter.clear();
312 				m_LastOptId = so->Id;
313 				return CmdLineParser::RESULT_OPT;
314 			}
315 		}
316 	}
317 	else
318 	{
319 		if (!ReadNextArg(&m_LastArg))
320 		{
321 			m_LastParameter.clear();
322 			m_LastOptId = 0;
323 			return CmdLineParser::RESULT_END;
324 		}
325 
326 		if (!m_LastArg.empty() && m_LastArg[0] == '-')
327 		{
328 			if (m_LastArg.length() > 1 && m_LastArg[1] == '-')
329 			{
330 				size_t EqualIndex = m_LastArg.find('=', 2);
331 				if (EqualIndex != std::string::npos)
332 				{
333 					LONG_OPT *lo = FindLongOpt(m_LastArg.substr(2, EqualIndex-2));
334 					if (lo == NULL || lo->Parameter == false)
335 					{
336 						m_LastOptId = 0;
337 						m_LastParameter.clear();
338 						return CmdLineParser::RESULT_ERROR;
339 					}
340 					m_LastParameter = m_LastArg.substr(EqualIndex+1);
341 					m_LastOptId = lo->Id;
342 					return CmdLineParser::RESULT_OPT;
343 				}
344 				else
345 				{
346 					LONG_OPT *lo = FindLongOpt(m_LastArg.substr(2));
347 					if (lo == NULL)
348 					{
349 						m_LastOptId = 0;
350 						m_LastParameter.clear();
351 						return CmdLineParser::RESULT_ERROR;
352 					}
353 					if (lo->Parameter)
354 					{
355 						if (!ReadNextArg(&m_LastParameter))
356 						{
357 							m_LastOptId = 0;
358 							m_LastParameter.clear();
359 							return CmdLineParser::RESULT_ERROR;
360 						}
361 					}
362 					else
363 						m_LastParameter.clear();
364 					m_LastOptId = lo->Id;
365 					return CmdLineParser::RESULT_OPT;
366 				}
367 			}
368 			else
369 			{
370 				if (m_LastArg.length() < 2)
371 				{
372 					m_LastOptId = 0;
373 					m_LastParameter.clear();
374 					return CmdLineParser::RESULT_ERROR;
375 				}
376 				SHORT_OPT *so = FindShortOpt(m_LastArg[1]);
377 				if (so == NULL)
378 				{
379 					m_LastOptId = 0;
380 					m_LastParameter.clear();
381 					return CmdLineParser::RESULT_ERROR;
382 				}
383 				if (so->Parameter)
384 				{
385 					if (m_LastArg.length() == 2)
386 					{
387 						if (!ReadNextArg(&m_LastParameter))
388 						{
389 							m_LastOptId = 0;
390 							m_LastParameter.clear();
391 							return CmdLineParser::RESULT_ERROR;
392 						}
393 						m_LastOptId = so->Id;
394 						return CmdLineParser::RESULT_OPT;
395 					}
396 					else if (m_LastArg[2] == '=')
397 					{
398 						m_LastParameter = m_LastArg.substr(3);
399 						m_LastOptId = so->Id;
400 						return CmdLineParser::RESULT_OPT;
401 					}
402 					else
403 					{
404 						m_LastParameter = m_LastArg.substr(2);
405 						m_LastOptId = so->Id;
406 						return CmdLineParser::RESULT_OPT;
407 					}
408 				}
409 				else
410 				{
411 					if (m_LastArg.length() == 2)
412 					{
413 						m_LastParameter.clear();
414 						m_LastOptId = so->Id;
415 						return CmdLineParser::RESULT_OPT;
416 					}
417 					else
418 					{
419 						m_InsideMultioption = true;
420 						m_LastArgIndex = 2;
421 
422 						m_LastParameter.clear();
423 						m_LastOptId = so->Id;
424 						return CmdLineParser::RESULT_OPT;
425 					}
426 				}
427 			}
428 		}
429 		else if (!m_LastArg.empty() && m_LastArg[0] == '/')
430 		{
431 			size_t EqualIndex = m_LastArg.find('=', 1);
432 			if (EqualIndex != std::string::npos)
433 			{
434 				if (EqualIndex == 2)
435 				{
436 					SHORT_OPT *so = FindShortOpt(m_LastArg[1]);
437 					if (so != NULL)
438 					{
439 						if (so->Parameter == false)
440 						{
441 							m_LastOptId = 0;
442 							m_LastParameter.clear();
443 							return CmdLineParser::RESULT_ERROR;
444 						}
445 						m_LastParameter = m_LastArg.substr(EqualIndex+1);
446 						m_LastOptId = so->Id;
447 						return CmdLineParser::RESULT_OPT;
448 					}
449 				}
450 				LONG_OPT *lo = FindLongOpt(m_LastArg.substr(1, EqualIndex-1));
451 				if (lo == NULL || lo->Parameter == false)
452 				{
453 					m_LastOptId = 0;
454 					m_LastParameter.clear();
455 					return CmdLineParser::RESULT_ERROR;
456 				}
457 				m_LastParameter = m_LastArg.substr(EqualIndex+1);
458 				m_LastOptId = lo->Id;
459 				return CmdLineParser::RESULT_OPT;
460 			}
461 			else
462 			{
463 				if (m_LastArg.length() == 2)
464 				{
465 					SHORT_OPT *so = FindShortOpt(m_LastArg[1]);
466 					if (so != NULL)
467 					{
468 						if (so->Parameter)
469 						{
470 							if (!ReadNextArg(&m_LastParameter))
471 							{
472 								m_LastOptId = 0;
473 								m_LastParameter.clear();
474 								return CmdLineParser::RESULT_ERROR;
475 							}
476 						}
477 						else
478 							m_LastParameter.clear();
479 						m_LastOptId = so->Id;
480 						return CmdLineParser::RESULT_OPT;
481 					}
482 				}
483 				LONG_OPT *lo = FindLongOpt(m_LastArg.substr(1));
484 				if (lo == NULL)
485 				{
486 					m_LastOptId = 0;
487 					m_LastParameter.clear();
488 					return CmdLineParser::RESULT_ERROR;
489 				}
490 				if (lo->Parameter)
491 				{
492 					if (!ReadNextArg(&m_LastParameter))
493 					{
494 						m_LastOptId = 0;
495 						m_LastParameter.clear();
496 						return CmdLineParser::RESULT_ERROR;
497 					}
498 				}
499 				else
500 					m_LastParameter.clear();
501 				m_LastOptId = lo->Id;
502 				return CmdLineParser::RESULT_OPT;
503 			}
504 		}
505 		else
506 		{
507 			m_LastOptId = 0;
508 			m_LastParameter = m_LastArg;
509 			return CmdLineParser::RESULT_PARAMETER;
510 		}
511 	}
512 }
513 
GetOptId()514 uint32_t CmdLineParser::GetOptId()
515 {
516 	return m_LastOptId;
517 }
518 
GetParameter()519 const std::string & CmdLineParser::GetParameter()
520 {
521 	return m_LastParameter;
522 }
523 
524 ////////////////////////////////////////////////////////////////////////////////
525 // Glolals
526 
527 /*
528 
529 void SetConsoleColor(CONSOLE_COLOR color)
530 {
531     WORD attr = 0;
532     switch(color)
533     {
534     case CONSOLE_COLOR::INFO:
535         attr = FOREGROUND_INTENSITY;;
536         break;
537     case CONSOLE_COLOR::NORMAL:
538         attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
539         break;
540     case CONSOLE_COLOR::WARNING:
541         attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
542         break;
543     case CONSOLE_COLOR::ERROR_:
544         attr = FOREGROUND_RED | FOREGROUND_INTENSITY;
545         break;
546     default:
547         assert(0);
548     }
549 
550     HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
551     SetConsoleTextAttribute(out, attr);
552 }
553 
554 void PrintMessage(CONSOLE_COLOR color, const char* msg)
555 {
556     if(color != CONSOLE_COLOR::NORMAL)
557         SetConsoleColor(color);
558 
559     printf("%s\n", msg);
560 
561     if (color != CONSOLE_COLOR::NORMAL)
562         SetConsoleColor(CONSOLE_COLOR::NORMAL);
563 }
564 
565 void PrintMessage(CONSOLE_COLOR color, const wchar_t* msg)
566 {
567     if(color != CONSOLE_COLOR::NORMAL)
568         SetConsoleColor(color);
569 
570     wprintf(L"%s\n", msg);
571 
572     if (color != CONSOLE_COLOR::NORMAL)
573         SetConsoleColor(CONSOLE_COLOR::NORMAL);
574 }
575 
576 static const size_t CONSOLE_SMALL_BUF_SIZE = 256;
577 
578 void PrintMessageV(CONSOLE_COLOR color, const char* format, va_list argList)
579 {
580 	size_t dstLen = (size_t)::_vscprintf(format, argList);
581 	if(dstLen)
582 	{
583 		bool useSmallBuf = dstLen < CONSOLE_SMALL_BUF_SIZE;
584 		char smallBuf[CONSOLE_SMALL_BUF_SIZE];
585 		std::vector<char> bigBuf(useSmallBuf ? 0 : dstLen + 1);
586 		char* bufPtr = useSmallBuf ? smallBuf : bigBuf.data();
587 		::vsprintf_s(bufPtr, dstLen + 1, format, argList);
588 		PrintMessage(color, bufPtr);
589 	}
590 }
591 
592 void PrintMessageV(CONSOLE_COLOR color, const wchar_t* format, va_list argList)
593 {
594 	size_t dstLen = (size_t)::_vcwprintf(format, argList);
595 	if(dstLen)
596 	{
597 		bool useSmallBuf = dstLen < CONSOLE_SMALL_BUF_SIZE;
598 		wchar_t smallBuf[CONSOLE_SMALL_BUF_SIZE];
599 		std::vector<wchar_t> bigBuf(useSmallBuf ? 0 : dstLen + 1);
600 		wchar_t* bufPtr = useSmallBuf ? smallBuf : bigBuf.data();
601 		::vswprintf_s(bufPtr, dstLen + 1, format, argList);
602 		PrintMessage(color, bufPtr);
603 	}
604 }
605 
606 void PrintMessageF(CONSOLE_COLOR color, const char* format, ...)
607 {
608 	va_list argList;
609 	va_start(argList, format);
610 	PrintMessageV(color, format, argList);
611 	va_end(argList);
612 }
613 
614 void PrintMessageF(CONSOLE_COLOR color, const wchar_t* format, ...)
615 {
616 	va_list argList;
617 	va_start(argList, format);
618 	PrintMessageV(color, format, argList);
619 	va_end(argList);
620 }
621 
622 void PrintWarningF(const char* format, ...)
623 {
624 	va_list argList;
625 	va_start(argList, format);
626 	PrintMessageV(CONSOLE_COLOR::WARNING, format, argList);
627 	va_end(argList);
628 }
629 
630 void PrintWarningF(const wchar_t* format, ...)
631 {
632 	va_list argList;
633 	va_start(argList, format);
634 	PrintMessageV(CONSOLE_COLOR::WARNING, format, argList);
635 	va_end(argList);
636 }
637 
638 void PrintErrorF(const char* format, ...)
639 {
640 	va_list argList;
641 	va_start(argList, format);
642 	PrintMessageV(CONSOLE_COLOR::WARNING, format, argList);
643 	va_end(argList);
644 }
645 
646 void PrintErrorF(const wchar_t* format, ...)
647 {
648 	va_list argList;
649 	va_start(argList, format);
650 	PrintMessageV(CONSOLE_COLOR::WARNING, format, argList);
651 	va_end(argList);
652 }
653 */
654 
SecondsToFriendlyStr(float seconds,std::string & out)655 void SecondsToFriendlyStr(float seconds, std::string& out)
656 {
657     if(seconds == 0.f)
658     {
659         out = "0";
660         return;
661     }
662 
663     if (seconds < 0.f)
664 	{
665 		out = "-";
666         seconds = -seconds;
667 	}
668 	else
669 	{
670 		out.clear();
671 	}
672 
673 	char s[32];
674 
675     // #.### ns
676     if(seconds < 1e-6)
677     {
678         sprintf_s(s, "%.3f ns", seconds * 1e9);
679         out += s;
680     }
681     // #.### us
682     else if(seconds < 1e-3)
683     {
684         sprintf_s(s, "%.3f us", seconds * 1e6);
685         out += s;
686     }
687     // #.### ms
688     else if(seconds < 1.f)
689     {
690         sprintf_s(s, "%.3f ms", seconds * 1e3);
691         out += s;
692     }
693     // #.### s
694     else if(seconds < 60.f)
695     {
696         sprintf_s(s, "%.3f s", seconds);
697         out += s;
698     }
699     else
700     {
701 	    uint64_t seconds_u = (uint64_t)seconds;
702 	    // "#:## min"
703 	    if (seconds_u < 3600)
704 	    {
705 		    uint64_t minutes = seconds_u / 60;
706 		    seconds_u -= minutes * 60;
707             sprintf_s(s, "%llu:%02llu min", minutes, seconds_u);
708             out += s;
709 	    }
710 	    // "#:##:## h"
711 	    else
712 	    {
713 		    uint64_t minutes = seconds_u / 60;
714             seconds_u -= minutes * 60;
715 		    uint64_t hours = minutes / 60;
716 		    minutes -= hours * 60;
717             sprintf_s(s, "%llu:%02llu:%02llu h", hours, minutes, seconds_u);
718             out += s;
719 	    }
720     }
721 }
722