@@ -1161,6 +1161,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
11611161struct lineptr * hlineptr ,
11621162* dlineptr ;
11631163bool is_pager = false;
1164+ int output_columns = 0 ;/* Width of interactive console */
11641165
11651166if (cancel_pressed )
11661167return ;
@@ -1234,24 +1235,86 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
12341235fprintf (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+ unsignedint 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 */
12381299for (i = 0 ,ptr = cont -> cells ;* ptr ;i ++ ,ptr ++ )
12391300{
12401301printTextRule pos ;
1241- int line_count ,
1302+ int dline ,
1303+ hline ,
12421304dcomplete ,
1243- hcomplete ;
1305+ hcomplete ,
1306+ offset ,
1307+ chars_to_output ;
12441308
12451309if (cancel_pressed )
12461310break ;
12471311
12481312if (i == 0 )
12491313pos = PRINT_RULE_TOP ;
1250- else if (!(* (ptr + 1 )))
1251- pos = PRINT_RULE_BOTTOM ;
12521314else
12531315pos = PRINT_RULE_MIDDLE ;
12541316
1317+ /* Print record header (e.g. "[ RECORD N ]") above each record */
12551318if (i %cont -> ncolumns == 0 )
12561319{
12571320if (!opt_tuples_only )
@@ -1270,48 +1333,120 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
12701333pg_wcsformat ((const unsignedchar * )* ptr ,strlen (* ptr ),encoding ,
12711334dlineptr ,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 ;
12741339dcomplete = hcomplete = 0 ;
1340+ offset = 0 ;
1341+ chars_to_output = dlineptr [dline ].width ;
12751342while (!dcomplete || !hcomplete )
12761343{
1344+ /* Left border */
12771345if (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) */
12791349if (!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 );
12851371hcomplete = 1 ;
1372+ }
12861373}
12871374else
1288- fprintf (fout ,"%*s" ,hwidth ,"" );
1375+ {
1376+ /* Header exhausted but more data for column */
1377+ fprintf (fout ,"%*s" ,hwidth + 2 ,"" );
1378+ }
12891379
1380+ /* Separator */
12901381if (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 */
12951394if (!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 );
13051433dcomplete = 1 ;
1434+ }
1435+
1436+ if (opt_border == 2 )
1437+ fputs (dformat -> rightvrule ,fout );
1438+
1439+ fputs ("\n" ,fout );
13061440}
13071441else
13081442{
1443+ /* data exhausted (this can occur if header is longer than the
1444+ * data due to newlines in the header) */
13091445if (opt_border < 2 )
1310- fputc ( '\n' ,fout );
1446+ fputs ( "\n" ,fout );
13111447else
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