@@ -1161,6 +1161,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
11611161 struct lineptr * hlineptr ,
11621162 * dlineptr ;
11631163 bool is_pager = false;
1164+ int output_columns = 0 ; /* Width of interactive console */
11641165
11651166 if (cancel_pressed )
11661167 return ;
@@ -1234,24 +1235,86 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
12341235 fprintf (fout , "%s\n" , cont -> title );
12351236 }
12361237
1238+ /*
1239+ * Choose target output width: \pset columns, or $COLUMNS, or ioctl
1240+ */
1241+ if (cont -> opt -> columns > 0 )
1242+ output_columns = cont -> opt -> columns ;
1243+ else if ((fout == stdout && isatty (fileno (stdout ))) || is_pager )
1244+ {
1245+ if (cont -> opt -> env_columns > 0 )
1246+ output_columns = cont -> opt -> env_columns ;
1247+ #ifdef TIOCGWINSZ
1248+ else
1249+ {
1250+ struct winsize screen_size ;
1251+
1252+ if (ioctl (fileno (stdout ), TIOCGWINSZ , & screen_size ) != -1 )
1253+ output_columns = screen_size .ws_col ;
1254+ }
1255+ #endif
1256+ }
1257+
1258+ if (cont -> opt -> format == PRINT_WRAPPED )
1259+ {
1260+ /* Calculate the available width to wrap the columns to after
1261+ * subtracting the maximum header width and separators. At a minimum
1262+ * enough to print "[ RECORD N ]" */
1263+ unsigned int width , swidth ;
1264+
1265+ if (opt_border == 0 )
1266+ swidth = 1 ; /* "header data" */
1267+ else if (opt_border == 1 )
1268+ swidth = 3 ; /* "header | data" */
1269+ else if (opt_border > 1 )
1270+ swidth = 7 ; /* "| header | data |" */
1271+
1272+ /* Wrap to maximum width */
1273+ width = dwidth + swidth + hwidth ;
1274+ if ((output_columns > 0 ) && (width > output_columns ))
1275+ {
1276+ dwidth = output_columns - hwidth - swidth ;
1277+ width = output_columns ;
1278+ }
1279+
1280+ /* Wrap to minimum width */
1281+ if (!opt_tuples_only )
1282+ {
1283+ int delta = 1 + log10 (cont -> nrows ) - width ;
1284+ if (opt_border == 0 )
1285+ delta += 6 ; /* "* RECORD " */
1286+ else if (opt_border == 1 )
1287+ delta += 10 ; /* "-[ RECORD ]" */
1288+ else if (opt_border == 2 )
1289+ delta += 15 ; /* "+-[ RECORD ]-+" */
1290+
1291+ if (delta > 0 )
1292+ dwidth += delta ;
1293+ }
1294+ else if (dwidth < 3 )
1295+ dwidth = 3 ;
1296+ }
1297+
12371298 /* print records */
12381299 for (i = 0 , ptr = cont -> cells ; * ptr ; i ++ , ptr ++ )
12391300 {
12401301 printTextRule pos ;
1241- int line_count ,
1302+ int dline ,
1303+ hline ,
12421304 dcomplete ,
1243- hcomplete ;
1305+ hcomplete ,
1306+ offset ,
1307+ chars_to_output ;
12441308
12451309 if (cancel_pressed )
12461310 break ;
12471311
12481312 if (i == 0 )
12491313 pos = PRINT_RULE_TOP ;
1250- else if (!(* (ptr + 1 )))
1251- pos = PRINT_RULE_BOTTOM ;
12521314 else
12531315 pos = PRINT_RULE_MIDDLE ;
12541316
1317+ /* Print record header (e.g. "[ RECORD N ]") above each record */
12551318 if (i % cont -> ncolumns == 0 )
12561319 {
12571320 if (!opt_tuples_only )
@@ -1270,48 +1333,120 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
12701333 pg_wcsformat ((const unsigned char * ) * ptr , strlen (* ptr ), encoding ,
12711334 dlineptr , dheight );
12721335
1273- line_count = 0 ;
1336+ /* Loop through header and data in parallel dealing with newlines and
1337+ * wrapped lines until they're both exhausted */
1338+ dline = hline = 0 ;
12741339 dcomplete = hcomplete = 0 ;
1340+ offset = 0 ;
1341+ chars_to_output = dlineptr [dline ].width ;
12751342 while (!dcomplete || !hcomplete )
12761343 {
1344+ /* Left border */
12771345 if (opt_border == 2 )
1278- fprintf (fout , "%s " , dformat -> leftvrule );
1346+ fprintf (fout , "%s" , dformat -> leftvrule );
1347+
1348+ /* Header (never wrapped so just need to deal with newlines) */
12791349 if (!hcomplete )
12801350 {
1281- fprintf (fout , "%-s%*s" , hlineptr [line_count ].ptr ,
1282- hwidth - hlineptr [line_count ].width , "" );
1351+ int swidth , twidth = hwidth + 1 ;
1352+ fputs (hline ? format -> header_nl_left : " " , fout );
1353+ strlen_max_width ((char * ) hlineptr [hline ].ptr , & twidth ,
1354+ encoding );
1355+ fprintf (fout , "%-s" , hlineptr [hline ].ptr );
1356+
1357+ swidth = hwidth - twidth ;
1358+ if (swidth > 0 ) /* spacer */
1359+ fprintf (fout , "%*s" , swidth , " " );
12831360
1284- if (!hlineptr [line_count + 1 ].ptr )
1361+ if (hlineptr [hline + 1 ].ptr )
1362+ {
1363+ /* More lines after this one due to a newline */
1364+ fputs (format -> header_nl_right , fout );
1365+ hline ++ ;
1366+ }
1367+ else
1368+ {
1369+ /* This was the last line of the header */
1370+ fputs (" " , fout );
12851371 hcomplete = 1 ;
1372+ }
12861373 }
12871374 else
1288- fprintf (fout , "%*s" , hwidth , "" );
1375+ {
1376+ /* Header exhausted but more data for column */
1377+ fprintf (fout , "%*s" , hwidth + 2 , "" );
1378+ }
12891379
1380+ /* Separator */
12901381 if (opt_border > 0 )
1291- fprintf (fout , " %s " , dformat -> midvrule );
1292- else
1293- fputc (' ' , fout );
1382+ {
1383+ if (offset )
1384+ fputs (format -> midvrule_wrap , fout );
1385+ else if (!dline )
1386+ fputs (dformat -> midvrule , fout );
1387+ else if (dline )
1388+ fputs (format -> midvrule_nl , fout );
1389+ else
1390+ fputs (format -> midvrule_blank , fout );
1391+ }
12941392
1393+ /* Data */
12951394 if (!dcomplete )
12961395 {
1297- if (opt_border < 2 )
1298- fprintf (fout , "%s\n" , dlineptr [line_count ].ptr );
1299- else
1300- fprintf (fout , "%-s%*s %s\n" , dlineptr [line_count ].ptr ,
1301- dwidth - dlineptr [line_count ].width , "" ,
1302- dformat -> rightvrule );
1396+ int target_width ,
1397+ bytes_to_output ,
1398+ swidth ;
1399+
1400+ fputs (!dcomplete && !offset ? " " : format -> wrap_left , fout );
13031401
1304- if (!dlineptr [line_count + 1 ].ptr )
1402+ target_width = dwidth ;
1403+ bytes_to_output = strlen_max_width (dlineptr [dline ].ptr + offset ,
1404+ & target_width , encoding );
1405+ fputnbytes (fout , (char * )(dlineptr [dline ].ptr + offset ),
1406+ bytes_to_output );
1407+
1408+ chars_to_output -= target_width ;
1409+ offset += bytes_to_output ;
1410+
1411+ /* spacer */
1412+ swidth = dwidth - target_width ;
1413+ if (swidth > 0 )
1414+ fprintf (fout , "%*s" , swidth , "" );
1415+
1416+ if (chars_to_output )
1417+ {
1418+ /* continuing a wrapped column */
1419+ fputs (format -> wrap_right , fout );
1420+ }
1421+ else if (dlineptr [dline + 1 ].ptr )
1422+ {
1423+ /* reached a newline in the column */
1424+ fputs (format -> nl_right , fout );
1425+ dline ++ ;
1426+ offset = 0 ;
1427+ chars_to_output = dlineptr [dline ].width ;
1428+ }
1429+ else
1430+ {
1431+ /* reached the end of the cell */
1432+ fputs (" " , fout );
13051433 dcomplete = 1 ;
1434+ }
1435+
1436+ if (opt_border == 2 )
1437+ fputs (dformat -> rightvrule , fout );
1438+
1439+ fputs ("\n" , fout );
13061440 }
13071441 else
13081442 {
1443+ /* data exhausted (this can occur if header is longer than the
1444+ * data due to newlines in the header) */
13091445 if (opt_border < 2 )
1310- fputc ( '\n' , fout );
1446+ fputs ( "\n" , fout );
13111447 else
1312- fprintf (fout , "%*s %s\n" , dwidth , "" , dformat -> rightvrule );
1448+ fprintf (fout , "%*s %s\n" , dwidth , "" , dformat -> rightvrule );
13131449 }
1314- line_count ++ ;
13151450 }
13161451 }
13171452
0 commit comments