25 Jan, 2010, Crelin wrote in the 1st comment:
Votes: 0
Basically my issue is this: I'm taking steps to align the who list properly and the clan names which go before the character name are not all the same size. The fix I want is for it to space them clan names as
i.e.:
[  Adventurer   ]
[ Hell's Winter ]
[Druidic Circles]


so as you can see, they are all even in character length and spaced more to the right than left if an odd number of spaces is needed. I can easily do this editing guild.dat with each new clan but I use an OLC cedit code that I want this to be doable with, and my client deletes extra spaces so they always end up left aligned. (meaning future admins clients could do the same). Since the []' brackets are automatically added, I could simply remove that and that would allow for the extra spaces after the ' brackets are automatically added, I could simply remove that and that would allow for the extra spaces after the [ in doing 'cedit_who' to fix the problem but are there any simply codes to check for string length and add spaces before and after the string as necesarry to conform to a limit? Sorry for the long post about a potentially small problem, but I'm curious and wanted to provide as much information as possible for the answer I'm seeking.
25 Jan, 2010, David Haley wrote in the 2nd comment:
Votes: 0
Yes, it's most definitely possible to write code to center a string. In pseudo-code…

center_string(str, width)
len = get length of string
if len > width then
return str
num_left = (width-len)/2
num_right = width-len-num_left
return " " * num_left + str + " " * num_right
end
25 Jan, 2010, Crelin wrote in the 3rd comment:
Votes: 0
so basically with that I'd call center_string with the arguments of the string and the width I want it to end up as, however if the length of the string used for the argument is greather than the width I want the string to be, why would I return the argument since it'd be longer than I wanted? or was that a quick mishap?
25 Jan, 2010, David Haley wrote in the 4th comment:
Votes: 0
It wasn't a mishap; it was an assumption that you'd rather have the original string preserved than truncate it if it's too wide. But you might prefer to truncate it, it depends on what your application is.
25 Jan, 2010, Crelin wrote in the 5th comment:
Votes: 0
ohh, ok…well I guess what I'd do is set a limit in cedit_who to how long the string can be with a global limit set in merc.h so I can use that as the width too and if I ever decide to allow a clan with a longer name, just change that.
25 Jan, 2010, David Haley wrote in the 6th comment:
Votes: 0
Nothing prevents you from truncating it for display if that's what you want to do. You could of course also set a limit in the user interface for specifying clan names, yes.
25 Jan, 2010, Crelin wrote in the 7th comment:
Votes: 0
hehe, nod…well it's just I don't want to see truncated clan names as that can tend to end up looking odd :P
25 Jan, 2010, Scandum wrote in the 8th comment:
Votes: 0
Following might work with merc.
char *center_string(char *arg, int maxlen)
{
static char buf[MAX_STRING_LEN];
int arglen = UMIN(strlen(arg), maxlen);

memset(buf, ' ', maxlen);

memcpy(&buf[(maxlen - arglen) / 2], arg, arglen);

buf[maxlen] = 0;

return buf;
}
25 Jan, 2010, David Haley wrote in the 9th comment:
Votes: 0
Wow, that's kind of funky. You're trying to center a string, and you end up truncating the input string??

I'd try something more like…

const char* center_string(const char* str, size_t width)
{
static char result[MAX_STRING_LENGTH];
size_t len = strlen(str);
if (len >= width) {
return str;
}
size_t num_left = (width-len)/2;

// Left-side spaces:
for (size_t i = 0; i < num_left; i++) {
result[i] = ' ';
}
// Copy the string:
for (size_t i = num_left; i < len + num_left; i++) {
result[i] = str[i-num_left];
}
// Finally, fill in the right spaces:
for (size_t i = len + num_left; i < width; i++) {
result[i] = ' ';
}

// Terminate the string
result[width] = '\0';

return result;
}


As a disclaimer, I have not tested this or even thought about it very much. It's possible that there are off-by-one errors in there. But, it doesn't screw with the input string (which is a major no-no) and it also avoids double-copying into the result buffer.
25 Jan, 2010, quixadhal wrote in the 10th comment:
Votes: 0
Just a note, since I know many people like to stick colour codes in and around their titles…. the above code assumes every character in the string is displayable. If you do have colour tokens/control codes/etc, you'll need to strip those out or use an approach that calculates the actual visible length (the SmaugFUSS codebase has an example of that).
25 Jan, 2010, David Haley wrote in the 11th comment:
Votes: 0
Yes, Quix has a good point. I think that if you had a strlen_color function of sorts, you would use that to figure out the number of spaces you need. You would need to change the math afterward slightly to account for the fact that you're copying more characters than you can "see".

This is a lot easier in a language with support for string objects, incidentally…
25 Jan, 2010, Tyche wrote in the 12th comment:
Votes: 0
Dirty ugly way.
$ cat center.c 
#include <string.h>
#include <stdio.h>
center(const char * s,int w){
int sl = strlen(s), l = (w-sl)/2, r = (w-sl)-l;
printf("[%*s%s%*s]\n",l,"",s,r,"");}

int main() {
center("CLANS",15);
center("===============",15);
center("Whoop-Ass",15);
center("Huns",15);
center("Tiny Fairy Queens",15); // ugly
}

$ gcc center.c & ./a
[ CLANS ]
[===============]
[ Whoop-Ass ]
[ Huns ]
[ Tiny Fairy Queens ]
26 Jan, 2010, Bojack wrote in the 13th comment:
Votes: 0
For color since you are using a rom codebase im assuming, the call in act_wiz.c int colorstrlen takes the color codes out of the string and counts it.
int colorstrlen(char *argument)
{
char *str;
int strlength;

if (argument == NULL || argument[0] == '\0')
return 0;

strlength = 0;
str = argument;

while (*str != '\0')
{
if ( *str != '{' )
{
str++;
strlength++;
continue;
}

if (*(++str) == '{')
strlength++;

str++;
}
return strlength;
}
26 Jan, 2010, David Haley wrote in the 14th comment:
Votes: 0
It's really bad form to screw with the input string like that. It would be much better to just count the string's displayable characters, and work from there. After all, who says that we want to remove the color? We just want to center it correctly.
26 Jan, 2010, Bojack wrote in the 15th comment:
Votes: 0
It doesnt actually take the color codes out, it just doesnt count the codes is what I mean. You take out the coloring then you can find max string length and after do the spacing to center it. Basically what he could do is count the string without the color in it which is what colorstrlen does then you'll have the max argument length, after you can do the spacing portion of it. If you wanted to get further into it you could actually do a clan lookup (this would be for clan list command or related), find the longest clan name and make that the new length and do an ajustment more so no matter what the clan name is, itll auto adjust to keep the spacing centered.
26 Jan, 2010, David Haley wrote in the 16th comment:
Votes: 0
Sorry, you're entirely correct. I should have actually read the code :smile: I was thrown off by the statement "takes the color codes out of the string" and thought you meant that it modified the string, not that it counted the length without the color codes.
26 Jan, 2010, Tyche wrote in the 17th comment:
Votes: 0
$ cat center.c 
#include <string.h>
#include <stdio.h>
center(const char * s,int w){
int sl = strlen(s), tl = (w-sl)<0?0:(w-sl) , l = tl/2, r = tl-l;
printf("[%*s%.*s%*s]\n",l,"",w,s,r,"");
}

int main() {
center("CLANS",15);
center("===============",15);
center("Whoop-Ass Clan",15);
center("Huns",15);
center("Tiny Fairy Queens",15);
center("A really really long clan name",15);
center("A",15);
}

$ gcc center.c & ./a
[ CLANS ]
[===============]
[Whoop-Ass Clan ]
[ Huns ]
[Tiny Fairy Quee]
[A really really]
[ A ]


Actually it's not so bad, if you allow it to truncate the string.
26 Jan, 2010, David Haley wrote in the 18th comment:
Votes: 0
Tyche's version illustrates two things:
- Check standard libraries for functions like this because often something exists already. (In this case, printf and consequently sprintf)
- One- or two-letter variable names are a PITA. :evil:
26 Jan, 2010, Davion wrote in the 19th comment:
Votes: 0
David Haley said:
Tyche's version illustrates two things:
- One- or two-letter variable names are a PITA. :evil:


I had to change my font to figure out if he was subtracting a lowercase 'L' or the number one ;)
01 Feb, 2010, Bojack wrote in the 20th comment:
Votes: 0
So I was messing around with what you guys said and came up with this using tyche's part and mine but unfortunately it doesnt display the final output right in the mud. Still tinkering with it. What I was thinking though is coming up with a way that would do this with any string. Any ideas?

int colorstrlen(char *argument)
{
char *str;
int strlength;

if (argument == NULL || argument[0] == '\0')
return 0;

strlength = 0;
str = argument;

while (*str != '\0')
{
if ( *str != '{' )
{
str++;
strlength++;
continue;
}

if (*(++str) == '{')
strlength++;

str++;
}
return strlength;
}

char buf[MSL];
char temp[MSL];
int sn, i = 0, x = 0;
int sl = 0;

if (IS_NPC(ch))
return;

for (sn = 0; sn < (1 + top_clan); sn++)
{
if (clan_table[sn].name != '\0'
|| clan_table[sn].name != NULL)
{
i = colorstrlen(clan_table[sn].name);
}

// Check which name is bigger
if (x < i)
{
x = i;
sprintf (temp, "%s strlength %d\n\r", clan_table[sn].name, x);
sendch (temp, ch);
}
}

int l;
int r;

for (sn = 0; sn < (1 + top_clan); sn++)
{
if (clan_table[sn].name != '\0'
|| clan_table[sn].name != NULL)
{
sl = colorstrlen (clan_table[sn].name);
l = (x-sl)/2;
r = (x-sl)-L;
sprintf (buf, "{B[{c%*s%s%*s{B]{x", l, "",
clan_table[sn].name, r, "");
sendch (buf, ch);
}
}
0.0/32