473,320 Members | 2,024 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

REQ: Extended printf() with word-wrapping column format flag

Hi,
I am working on an existing code base in which a lot of data displayed
to the user is formatted in tables. Most tables are printed row-by-row
using printf() with "%[width]s" print conversion specification for
each column (e.g. printf(%10s %25s %15s\n", pszCol1, pszCol2,
pszCol3)). My problem is that when a string is longer the column's
width, it overflows the column and takes the table out of alignment.
What I want it to do is word-wrap within the column, thus keeping the
table aligned.
The most desirable solution for this is an extended printf() function,
which accepts another format-flag that specifies the field as
word-wrapping. For example (new format flag is '='):
xprintf("%=10s %=25s %=15s\n", pszCol1, pszCol2, pszCol3)

1. Can anyone point me to an implementation of such extended printf()?
2. If not, any other creative solutions are most welcome.

Thanks,
Rod
Nov 13 '05 #1
5 5260

"nimdez" <ni****@yahoo.com> wrote in message

I am working on an existing code base in which a lot of data displayed
to the user is formatted in tables.
What I want it to do is word-wrap within the column, thus keeping the
table aligned.

xprintf("%=10s %=25s %=15s\n", pszCol1, pszCol2, pszCol3)

2. If not, any other creative solutions are most welcome.

If you try to support all of printf()'s format specifiers then you will have
a huge job on.
However it should be possible to write a

printcolumns(const char *fmt, ...)

which only takes %s specifiers. You then do the wrapping within the
function.
Nov 13 '05 #2

On Sun, 10 Aug 2003, nimdez wrote:
[snip] The most desirable solution for this is an extended printf() function,
which accepts another format-flag that specifies the field as
word-wrapping. For example (new format flag is '='):
xprintf("%=10s %=25s %=15s\n", pszCol1, pszCol2, pszCol3)

1. Can anyone point me to an implementation of such extended printf()?
2. If not, any other creative solutions are most welcome.


I think you may have good luck examining the source code to various
"roguelike" computer games - for example, Angband and Nethack (although
maybe not Nethack for your purposes). These games typically have a
"status bar" on which are displayed messages such as "You hit the goblin
for 527 points of damage!", and spend a little CPU time trying to make
those messages look pretty. Word wrapping and such. (Any status-bar
game will have this sort of code somewhere, but roguelikes are
traditionally more open.)
However, wouldn't this be easier?
[extremely untested code]

int wrprintf(int llen, const char *fmt, ...)
{
va_list ap;
char buffer[REALLY_BIG_NUMBER];
int slen;
int start, end, i;
int rc;

/* Use the existing library */
va_start(ap, fmt);
rc = vsprintf(buffer, fmt, ap);
va_end(ap);

slen = strlen(buffer);

for (start = 0; start < slen-llen; )
{
end = start+llen;
while (! isspace(buffer[end])) {
--end;
if (end == start) {
end = start+llen;
break;
}
}

/* print one full line */
for (i=start; i < end; ++i)
putchar(buffer[i]);
/* end of line, go to next line */
putchar('\n');

start = end;
while (isspace(buffer[start]))
++start;
}

/* print last line */
for (i=start; i < slen; ++i)
putchar(buffer[i]);
putchar('\n');

return rc;
}
Now, if you want word wrapping within *each* column separately,
Excel-style, you'll need a lot more thinking in order to do
that in plain C.

HTH,
-Arthur

Nov 13 '05 #3
On 10 Aug 2003 06:57:40 -0700, ni****@yahoo.com (nimdez) wrote:
Hi,
I am working on an existing code base in which a lot of data displayed
to the user is formatted in tables. Most tables are printed row-by-row
using printf() with "%[width]s" print conversion specification for
each column (e.g. printf(%10s %25s %15s\n", pszCol1, pszCol2,
pszCol3)). My problem is that when a string is longer the column's
width, it overflows the column and takes the table out of alignment.
[snip]
2. If not, any other creative solutions are most welcome.


I took a simpler solution, which is to reduce the widths of subsequent
columns to bring the table back into alignment. The basic code to
this this is something like this (although to be robust you should
ensure that the '*' parameter is not zero or negative):

int column = 0;

column += printf( "%10s ", pszCol1 );
column += printf( "%*s ", 36 - column, pszCol2 );
column += printf( "%*s ", 52 - column, pszCol2 );
printf( "\n" );

Nick.

Nov 13 '05 #4

"nimdez" <ni****@yahoo.com> wrote in message

xprintf("%=10s %=25s %=15s\n", pszCol1, pszCol2, pszCol3)

The problem is it is difficult to pass most of the code on to vsprintf() to
do the work. This is because of the nature of variadic functions.

However this might be useful to you. (Tested slightly).

/*
print a series of strings and a format string, wrapping
to preserve columns.
Currently only the %<width>s format is supported
*/
void colprint(char *fmt, ...)
{
int nargs = 0;
char ***column;
int *tabs;
int *widths;
int i;
int ii;
int Npercent = 0;

int col = 0;
int width;
char *end;
char *str;
va_list vargs;
/*
In order to simplify the code, allocate enough space
here based on number % signs passed
*/
for(i=0;fmt[i];i++)
if(fmt[i] == '%')
Npercent++;

column = malloc(Npercent * sizeof(char **));
tabs = malloc(Npercent * sizeof(int));
widths = malloc(Npercent *sizeof(int));
if(!column || !tabs || !widths)
goto cleanup;

va_start(vargs, fmt);

while(*fmt)
{
if(*fmt == '%')
{
switch( getfieldtype(fmt) )
{
case '%':
putchar('%');
fmt += 2;
break;
case 's':
width = strtol(fmt+1, &end, 10);
tabs[nargs] = col;
widths[nargs] = width;

str = va_arg(vargs, char *);
column[nargs] = strwrap(str, width);
if(!column[nargs])
goto cleanup;

for(i=0;column[nargs][0][i];i++)
{
putchar( column[nargs][0][i] );
col++;
}
while(i<width)
{
putchar(' ');
col++;
i++;
}
nargs++;
while(*fmt != 's')
fmt++;
break;
/* add other fields here if you wish to support them */
default:
fprintf(stderr, "Format %c not recognised\n", getfieldtype(fmt));
return;
}
}
else
{
putchar(*fmt);
col++;
fmt++;
}
}

va_end(vargs);
printcolumns(column, tabs, widths, nargs);

cleanup:
for(i=0;i<nargs;i++)
{
for(ii=0;column[i][ii];ii++)
free(column[i][ii]);
free(column[i]);
}
if(column)
free(column);
if(tabs)
free(tabs);
if(widths)
free(widths);
}

/*
get the type of field we are passed.
*/
char getfieldtype(char *fmt)
{
assert(*fmt == '%');
fmt++;
if(*fmt == '%')
return '%';

while(*fmt && !isalpha(*fmt))
fmt++;

return *fmt;
}

/*
Prints the wrapped text in the right column.
cols - pointer to list of wrapped text
tabs - tab offset of each column
width - widths of each column
ncols - number of columns passed
*/
void printcolumns(char ***cols, int *tabs, int *widths, int ncols)
{
int i;
int ii;
int iii;
int *coldepth;
int maxdepth = 0;
int col;

coldepth = malloc(ncols * sizeof(int));

if(!coldepth)
return;

/* find the depth of each column (NULL-terminated list)
for(i=0;i<ncols;i++)
{
coldepth[i] = 0;
while(cols[i][coldepth[i]])
coldepth[i]++;
}

/* find the maximum depth */
for(i=0;i<ncols;i++)
if(maxdepth < coldepth[i])
maxdepth = coldepth[i];

/* print out the column */
for(i=1;i<maxdepth;i++)
{
col = 0;
for(ii=0;ii<ncols;ii++)
{
while(col < tabs[ii])
{
putchar(' ');
col++;
}
if(coldepth[ii] > i)
{
for(iii=0;cols[ii][i][iii];iii++)
{
putchar( cols[ii][i][iii] );
col++;
}
}
while(col < tabs[ii] + widths[ii])
{
putchar(' ');
col++;
}
}
putchar('\n');
}

free(coldepth);

}
/*
string-wrapping function.
Params: str - string to wrap
len - maximum length of column
Returns: NULL-terminated list of truncated strings
*/
char **strwrap(const char *str, int len)
{
char **answer = 0;
char **temp;
char *buff;
int nlines = 0;
int i;

while(*str)
{
temp = realloc(answer, (nlines + 2) * sizeof(char *));
if(!temp)
{
for(i=0;i<nlines;i++)
free(answer[i]);
free(answer);
return 0;
}
answer = temp;

buff = malloc(len+1);
if(!buff)
{
for(i=0;i<nlines;i++)
free(answer[i]);
free(answer);
return 0;
}

wrapline(buff, str, len);
answer[nlines++] = buff;
str += strlen(buff);
}

answer[nlines] = 0;

return answer;
}

/*
wrap a line of text
ret - return pointer for line
str - text to wrap
len - maximum length of line
*/
void wrapline(char *ret, const char *str, int len)
{
char *end;

if(len > (int) strlen(str))
len = strlen(str);

if(len < 1)
{
strcpy(ret, "");
return;
}

end = strchr(str, '\n');
if(end && end - str < len)
{
memcpy(ret, str, end - str + 1);
ret[end-str+1] = 0;
return;
}

memcpy(ret, str, len);
end = &ret[len-1];

if(str[len] != 0)
while(end > ret && !isspace(*end))
end--;

if(end > ret)
end[1] = 0;
else
ret[len] = 0;
}
Nov 13 '05 #5

"nimdez" <ni****@yahoo.com> wrote in message
news:e0**************************@posting.google.c om...
Hi,
I am working on an existing code base in which a lot of data displayed
to the user is formatted in tables. Most tables are printed row-by-row
using printf() with "%[width]s" print conversion specification for
each column (e.g. printf(%10s %25s %15s\n", pszCol1, pszCol2,
pszCol3)). My problem is that when a string is longer the column's
width, it overflows the column and takes the table out of alignment.
What I want it to do is word-wrap within the column, thus keeping the
table aligned.
The most desirable solution for this is an extended printf() function,
which accepts another format-flag that specifies the field as
word-wrapping. For example (new format flag is '='):
xprintf("%=10s %=25s %=15s\n", pszCol1, pszCol2, pszCol3)

1. Can anyone point me to an implementation of such extended printf()?
2. If not, any other creative solutions are most welcome.
Rather than trying to rewrite printf, I'd go for a two step approach:

setcolumnsize(10, 25, 15, 0);
xprintf(%10s|%25s|%15s", s1, s2, s3);

Where xprintf calls vsprintf, and then reprocesses the resulting |-separated
columnar text according to the previously defined column widths. (If you
expect to see | in your data, use another marker.)
Thanks,
Rod


--
Roger
Nov 13 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: John F Dutcher | last post by:
Can anyone comment on why the code shown in the Python error is in some way incorrect...or is there a problem with Python on my hoster's site ?? The highlites don't seem to show here...but line...
33
by: Kenneth Brody | last post by:
I know that passing printf() too few arguments, or arguments of the wrong type invokes UB. However, what about passing too many arguments, if the expected arguments are of the correct type? For...
0
by: Fabricio de Reuter Sperandio | last post by:
Hi everybody, I did an ASP.NET application to send a fax using the Extended Fax Service COM API. I am running Windows XP. The problem is: When I send Text files, it mens, the FaxDocument.Body...
3
by: chjiangwh | last post by:
hello,everybody I want to print extended ASCII codes in a windows console app. I want to print the chessboard in the console screen,using printf("%c",219) but it appears strange code. Anybody...
36
by: Debaser | last post by:
I've recently read in one of my old C books that puts() is a better function call with regard to performance than printf() in the following situation: puts("Some random text"); vs. ...
4
by: Peppie | last post by:
Hi all, I created a button in an Access form that opens MS Word. Now I want this button also to open a specific file. How do I code this? Would it also be possible to let the user select the...
4
by: sdlt85 | last post by:
Hi, Can someone help me with an idea on how to start writing a C++ code for generating greatest common divisor and the linear combination of two intergers represented as gcd(m, n)= mx + ny and...
11
by: Googy | last post by:
Hi friends!! As we know that the input parameters in a function is fixed when the function is defined but how does printf processes variable number of input arguments ? For example: 1....
13
by: ramif | last post by:
Is there a way to print extended ASCII in C?? I tried to code something, but it only displays strange symbols. here is my code: main() { char chr = 177; //stores the extended ASCII...
10
by: Rahul | last post by:
Hi Everyone, I had a query reg printf(). I heard that it can't be used in ISR's as it is non-re-enterant. I didn't get as to why printf is non-re-enterant and why non-re-enterant library can't...
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.