Changeset 95586 in vbox for trunk/src/VBox/Runtime/r3
- Timestamp:
- Jul 11, 2022 9:51:30 AM (3 years ago)
- svn:sync-xref-src-repo-rev:
- 152218
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/stream.cpp
r93115 r95586 45 45 #include <iprt/assert.h> 46 46 #include <iprt/alloc.h> 47 #include <iprt/ctype.h> 47 48 #include <iprt/err.h> 48 49 #include <iprt/param.h> … … 98 99 #endif 99 100 } RTSTREAM; 101 102 103 /** 104 * State for wrapped output (RTStrmWrappedPrintf, RTStrmWrappedPrintfV). 105 */ 106 typedef struct RTSTRMWRAPPEDSTATE 107 { 108 PRTSTREAM pStream; /**< The output stream. */ 109 uint32_t cchWidth; /**< The line width. */ 110 uint32_t cchLine; /**< The current line length (valid chars in szLine). */ 111 uint32_t cLines; /**< Number of lines written. */ 112 uint32_t cchIndent; /**< The indent (determined from the first line). */ 113 int rcStatus; /**< The output status. */ 114 uint8_t cchHangingIndent; /**< Hanging indent (from fFlags). */ 115 char szLine[0x1000+1]; /**< We must buffer output so we can do proper word splitting. */ 116 } RTSTRMWRAPPEDSTATE; 100 117 101 118 … … 1291 1308 } 1292 1309 1310 1311 1312 #define RTSTRMWRAPPED_F_LINE_OFFSET_MASK UINT32_C(0x00000fff) 1313 #define RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_MASK UINT32_C(0x000ff000) 1314 #define RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_SHIFT 12 1315 #define RTSTRMWRAPPED_F_HANGING_INDENT_MASK UINT32_C(0x01f00000) 1316 #define RTSTRMWRAPPED_F_HANGING_INDENT_SHIFT 20 1317 #define RTSTRMWRAPPED_F_HANGING_INDENT UINT32_C(0x80000000) 1318 1319 /** 1320 * Outputs @a cchIndent spaces. 1321 */ 1322 static void rtStrmWrapppedIndent(RTSTRMWRAPPEDSTATE *pState, uint32_t cchIndent) 1323 { 1324 static const char s_szSpaces[] = " "; 1325 while (cchIndent) 1326 { 1327 uint32_t cchToWrite = RT_MIN(cchIndent, sizeof(s_szSpaces) - 1); 1328 int rc = RTStrmWrite(pState->pStream, s_szSpaces, cchToWrite); 1329 if (RT_SUCCESS(rc)) 1330 cchIndent -= cchToWrite; 1331 else 1332 { 1333 pState->rcStatus = rc; 1334 break; 1335 } 1336 } 1337 } 1338 1339 1340 /** 1341 * Flushes the current line. 1342 * 1343 * @param pState The wrapped output state. 1344 * @param fPartial Set if partial flush due to buffer overflow, clear when 1345 * flushing due to '\n'. 1346 */ 1347 static void rtStrmWrappedFlushLine(RTSTRMWRAPPEDSTATE *pState, bool fPartial) 1348 { 1349 /* 1350 * Check indentation in case we need to split the line later. 1351 */ 1352 uint32_t cchIndent = pState->cchIndent; 1353 if (cchIndent == UINT32_MAX) 1354 { 1355 pState->cchIndent = 0; 1356 cchIndent = pState->cchHangingIndent; 1357 while (RT_C_IS_BLANK(pState->szLine[cchIndent])) 1358 cchIndent++; 1359 } 1360 1361 /* 1362 * Do the flushing. 1363 */ 1364 uint32_t cchLine = pState->cchLine; 1365 Assert(cchLine < sizeof(pState->szLine)); 1366 while (cchLine >= pState->cchWidth || !fPartial) 1367 { 1368 /* 1369 * Hopefully we don't need to do any wrapping ... 1370 */ 1371 uint32_t offSplit; 1372 if (pState->cchIndent + cchLine <= pState->cchWidth) 1373 { 1374 if (!fPartial) 1375 { 1376 rtStrmWrapppedIndent(pState, pState->cchIndent); 1377 pState->szLine[cchLine] = '\n'; 1378 int rc = RTStrmWrite(pState->pStream, pState->szLine, cchLine + 1); 1379 if (RT_FAILURE(rc)) 1380 pState->rcStatus = rc; 1381 pState->cLines += 1; 1382 pState->cchLine = 0; 1383 pState->cchIndent = UINT32_MAX; 1384 return; 1385 } 1386 1387 /* 1388 * ... no such luck. 1389 */ 1390 offSplit = cchLine; 1391 } 1392 else 1393 offSplit = pState->cchWidth - pState->cchIndent; 1394 1395 /* Find the start of the current word: */ 1396 while (offSplit > 0 && !RT_C_IS_BLANK(pState->szLine[offSplit - 1])) 1397 offSplit--; 1398 1399 /* Skip spaces. */ 1400 while (offSplit > 0 && RT_C_IS_BLANK(pState->szLine[offSplit - 1])) 1401 offSplit--; 1402 uint32_t offNextLine = offSplit; 1403 1404 /* If the first word + indent is wider than the screen width, so just output it in full. */ 1405 if (offSplit == 0) /** @todo Split words, look for hyphen... This code is currently a bit crude. */ 1406 { 1407 while (offSplit < cchLine && !RT_C_IS_BLANK(pState->szLine[offSplit])) 1408 offSplit++; 1409 offNextLine = offSplit; 1410 } 1411 1412 while (offNextLine < cchLine && RT_C_IS_BLANK(pState->szLine[offNextLine])) 1413 offNextLine++; 1414 1415 /* 1416 * Output and advance. 1417 */ 1418 rtStrmWrapppedIndent(pState, pState->cchIndent); 1419 int rc = RTStrmWrite(pState->pStream, pState->szLine, offSplit); 1420 if (RT_SUCCESS(rc)) 1421 rc = RTStrmPutCh(pState->pStream, '\n'); 1422 if (RT_FAILURE(rc)) 1423 pState->rcStatus = rc; 1424 1425 cchLine -= offNextLine; 1426 pState->cchLine = cchLine; 1427 pState->cLines += 1; 1428 pState->cchIndent = cchIndent; 1429 memmove(&pState->szLine[0], &pState->szLine[offNextLine], cchLine); 1430 } 1431 1432 /* The indentation level is reset for each '\n' we process, so only save cchIndent if partial. */ 1433 pState->cchIndent = fPartial ? cchIndent : UINT32_MAX; 1434 } 1435 1436 1437 /** 1438 * @callback_method_impl{FNRTSTROUTPUT} 1439 */ 1440 static DECLCALLBACK(size_t) rtStrmWrappedOutput(void *pvArg, const char *pachChars, size_t cbChars) 1441 { 1442 RTSTRMWRAPPEDSTATE *pState = (RTSTRMWRAPPEDSTATE *)pvArg; 1443 size_t const cchRet = cbChars; 1444 while (cbChars > 0) 1445 { 1446 if (*pachChars == '\n') 1447 { 1448 rtStrmWrappedFlushLine(pState, false /*fPartial*/); 1449 pachChars++; 1450 cbChars--; 1451 } 1452 else 1453 { 1454 const char *pszEol = (const char *)memchr(pachChars, '\n', cbChars); 1455 size_t cchToCopy = pszEol ? (size_t)(pszEol - pachChars) : cbChars; 1456 uint32_t cchLine = pState->cchLine; 1457 Assert(cchLine < sizeof(pState->szLine)); 1458 bool const fFlush = cchLine + cchToCopy >= sizeof(pState->szLine); 1459 if (fFlush) 1460 cchToCopy = cchToCopy - sizeof(pState->szLine) - 1; 1461 1462 pState->cchLine = cchLine + (uint32_t)cchToCopy; 1463 memcpy(&pState->szLine[cchLine], pachChars, cchToCopy); 1464 1465 pachChars += cchToCopy; 1466 cbChars -= cchToCopy; 1467 1468 if (fFlush) 1469 rtStrmWrappedFlushLine(pState, true /*fPartial*/); 1470 } 1471 } 1472 return cchRet; 1473 } 1474 1475 1476 RTDECL(int32_t) RTStrmWrappedPrintfV(PRTSTREAM pStream, uint32_t fFlags, const char *pszFormat, va_list va) 1477 { 1478 /* 1479 * Figure the output width and set up the rest of the output state. 1480 */ 1481 RTSTRMWRAPPEDSTATE State; 1482 State.pStream = pStream; 1483 State.cchLine = fFlags & RTSTRMWRAPPED_F_LINE_OFFSET_MASK; 1484 State.cLines = 0; 1485 State.rcStatus = VINF_SUCCESS; 1486 State.cchIndent = UINT32_MAX; 1487 State.cchHangingIndent = 0; 1488 if (fFlags & RTSTRMWRAPPED_F_HANGING_INDENT) 1489 { 1490 State.cchHangingIndent = (fFlags & RTSTRMWRAPPED_F_HANGING_INDENT_MASK) >> RTSTRMWRAPPED_F_HANGING_INDENT_SHIFT; 1491 if (!State.cchHangingIndent) 1492 State.cchHangingIndent = 4; 1493 } 1494 1495 int rc = RTStrmQueryTerminalWidth(pStream, &State.cchWidth); 1496 if (RT_SUCCESS(rc)) 1497 State.cchWidth = RT_MIN(State.cchWidth, RTSTRMWRAPPED_F_LINE_OFFSET_MASK + 1); 1498 else 1499 { 1500 State.cchWidth = (uint32_t)fFlags & RTSTRMWRAPPED_F_NON_TERMINAL_WIDTH_MASK; 1501 if (!State.cchWidth) 1502 State.cchWidth = 80; 1503 } 1504 if (State.cchWidth < 32) 1505 State.cchWidth = 32; 1506 //State.cchWidth -= 1; /* necessary here? */ 1507 1508 /* 1509 * Do the formatting. 1510 */ 1511 RTStrFormatV(rtStrmWrappedOutput, &State, NULL, NULL, pszFormat, va); 1512 1513 /* 1514 * Returning is simple if the buffer is empty. Otherwise we'll have to 1515 * perform a partial flush and write out whatever is left ourselves. 1516 */ 1517 if (RT_SUCCESS(State.rcStatus)) 1518 { 1519 if (State.cchLine == 0) 1520 return State.cLines << 16; 1521 1522 rtStrmWrappedFlushLine(&State, true /*fPartial*/); 1523 if (RT_SUCCESS(State.rcStatus) && State.cchLine > 0) 1524 { 1525 rtStrmWrapppedIndent(&State, State.cchIndent); 1526 State.rcStatus = RTStrmWrite(State.pStream, State.szLine, State.cchLine); 1527 } 1528 if (RT_SUCCESS(State.rcStatus)) 1529 return RT_MIN(State.cchIndent + State.cchLine, RTSTRMWRAPPED_F_LINE_OFFSET_MASK) | (State.cLines << 16); 1530 } 1531 return State.rcStatus; 1532 } 1533 1534 1535 RTDECL(int32_t) RTStrmWrappedPrintf(PRTSTREAM pStream, uint32_t fFlags, const char *pszFormat, ...) 1536 { 1537 va_list va; 1538 va_start(va, pszFormat); 1539 int32_t rcRet = RTStrmWrappedPrintfV(pStream, fFlags, pszFormat, va); 1540 va_end(va); 1541 return rcRet; 1542 } 1543
Note:
See TracChangeset
for help on using the changeset viewer.