13 Jul, 2010, Valo wrote in the 1st comment:
Votes: 0
I have a +sheet code that draws the title of an entry from the name of the attribute itself. For instance, the attribute: STRENGTHS_FISHING would show up as Fishing. I have it setup to handle spaces and multiple words, but when two words are used, the attribute STRENGTHS_KICK-BOXING shows up as Kick boxing instead of Kick Boxing. I was wondering if anyone knows how I can capitalize both words in the title. The code is shown below.

[setq(0,lcstr(sort(lattr(%#/strengths_*))))][iter(%q0,[ljust(edit(capstr(mid(##,strlen(strengths_),strlen(##))),-,%b),24)][switch(mod(#@,3),0,%r%b)])]

Any assistance would be appreciated.
13 Jul, 2010, Idealiad wrote in the 2nd comment:
Votes: 0
Yeah, you need a multi-word capstring. Funny, I was just reading something the other day about this. The mushcoder Faraday has a good collection of code on her Google code site, here's a link:

http://code.google.com/p/faramushcode/so...

Looking at that file I see this (prettified, go to the link to get the raw line if your client can't quote this in):

&FUN_CAPSTR_ALL Global Utility Functions=
iter(
%0,
capstr(##),
switch(%1,,%B,%1),
switch(%1,,%B,%1))

&FUNHELP_CAPSTR_ALL Global Utility Functions=
This function will capitalize each word of a multi-word string.
It defaults to a space-delimited string but you can pass a
delimiter if you want.%R%R
Usage: capstr_all(<string>,\[delimiter\])


Just shout if that doesn't make sense.
13 Jul, 2010, ralgith wrote in the 3rd comment:
Votes: 0
Discussion/Example in C:

http://www.daniweb.com/forums/thread7778...

Discussion/Example in C++:
http://www.mcculloughdesigns.com/blog/c-...

The following is untested, and not double checked. It should be pretty close to.
And using LOWER, UPPER, & from a modified version of strn_cmp from CircleMUD 3.1:
#define LOWER©   ((©>='A'  && © <= 'Z') ? (©+('a'-'A')) : ©)
#define UPPER© ((©>='a' && © <= 'z') ? (©+('A'-'a')) : ©)
/*
* str_cew: Function to capitalize the first letter each word in a string.
* All other letters in the string are returned returned in lower case.
* Returns: New string with each word capitalized, or NULL if fails.[s].
*
* Does not modify original string.
* If you wish to modify the original string, simply assign the new value back to it:
* string = char *strn_cew(string);
*/
char *str_cew(char *argument)
{
char first_arg[MAX_STRING_LENGTH];

if (!argument) {
log("SYSERR: str_cew received a NULL pointer!");
*first_arg = '\0';
return (NULL);
}

/* CircleMUD function to strip leading spaces from the string */
skip_spaces(&argument);

first_arg = '\0';
*first_arg = UPPER(*argument);
argument++;
while (*argument) {
if (isspace(*argument)) {
*(first_arg++) = *argument;
argument++;
*(first_arg++) = UPPER(*argument);
} else {
*(first_arg++) = LOWER(*argument);
}
argument++;
}

return (first_arg);
}
13 Jul, 2010, Valo wrote in the 4th comment:
Votes: 0
I have added the functions that Idealiad gave and it still doesn't work. I am wondering if there is anything that I need to change in it from PennMUSH to TinyMUX. I am running on TinyMUX. Ralgith, since that was set for CircleMUD, would it also work on TinyMUX?
13 Jul, 2010, ralgith wrote in the 5th comment:
Votes: 0
You would have to re-write it, and it doesn't work as is anyways. I've got a few errors in it. I'm actually fixing it for my own MUD. I'm too tired right now to finish it. Once I finish I'll repost it. Then you can try and modify it to work on your MUD, though if you add the UPPER and LOWER it should work as it is (will be when finished) really. There isn't anything in it MUD specific except the skip_spaces, which I can post that too if your MUD doesn't have something to perform that function.
13 Jul, 2010, Idealiad wrote in the 6th comment:
Votes: 0
You would need to add the C function to your mux's functions, which may not be a trivial task.

Could you re-post your modified code? How are you calling the capstr_all?
13 Jul, 2010, ralgith wrote in the 7th comment:
Votes: 0
Sorry, didn't pay close enough attention to realize that TinyMUX isn't written in C… did I mention that I was tired?

Except that from tinymux.org docs link to the readme.txt:
TinyMUX 2.4 is written in a mix of C and C++

All he should have to do is add a prototype for it in an appropriate header file. For example, I'm adding my str_cew function to utils.c and I have it prototyped in utils.h…

I know I said I was too tired to finish this, but I couldn't sleep. So. Here it is…

First, me on my MUD using it with my imm via my testing command (which is usually just send_to_char(ch, "Does Nothing!\r\n"); unless I've placed test code in it like right now)
Quote
50000Hp 50000Ma 50000Mv> immtest boogie woogie
str_cew output: Boogie Woogie


Now for the do_immtest code so you can see how its used
The ACMD is a CircleMUD MACRO for standard command function declaration
ACMD(do_immtest)
{
char buf[MAX_STRING_LENGTH];
str_cew(argument, buf);
send_to_char(ch, "str_cew output: %s\r\n", buf);
}


The prototype for str_cew in utils.h
I'm considering changing this from void to int and having it return either the number of words capped, OR the total length in bytes… any input on this?
void str_cew(char *argument, char *new_arg);


The function in utils.c, as I said above for the prototype, considering changing this to int and doing some type of return value.
/*
* str_cew: Function to capitalize the first letter each word in a string.
* All other letters in the string are returned returned in lower case.
*
* Does not modify original string. Returns void.
*/
void str_cew(char *argument, char *new_arg)
{
if (!argument || !*argument) {
log("SYSERR: str_cew received a NULL pointer!");
*new_arg = '\0';
return;
}

if (argument == '\0') {
log("SYSERR: str_cew received no argument!");
*new_arg = '\0';
return;
}

/* CircleMUD function to strip leading spaces from the string */
skip_spaces(&argument);

*(new_arg++) = UPPER(*argument);
argument++;
while (*argument) {
if (isspace(*argument)) {
*(new_arg++) = LOWER(*argument);
argument++;
if (*argument != '\0')
*(new_arg++) = UPPER(*argument);
} else {
*(new_arg++) = LOWER(*argument);
}
if (*argument != '\0')
argument++;
}

*new_arg = '\0';

return;
}


Don't forget the UPPER and LOWER macros from the other post above if you want to use this. For me, those are also defined in utils.h
I'm happy to help if you need it.
13 Jul, 2010, Valo wrote in the 8th comment:
Votes: 0
Okay. I'll try all that. I appreciate all your help guys. Here's the updated code I'm using.


[setq(0,lcstr(sort(lattr(%#/strengths_*))))][iter(%q0,[ljust(edit(capstr_all(mid(##,strlen(strengths_),strlen(##))),-,%b),24)][switch(mod(#@,3),0,%r%b)])]
13 Jul, 2010, ralgith wrote in the 9th comment:
Votes: 0
Any time. Its almost 1am here, so I'm off to bed. But if you need anything I'll be checking in tomorrow. Just leave a post. :D
13 Jul, 2010, Idealiad wrote in the 10th comment:
Votes: 0
Valo, did you add capstr_all as a @function? Without that calling it won't work.

@ralgith, adding the function in the C code is not a bad idea in itself, but most programming in mux is done with the runtime scripting language (called mushcode or softcode). Functions in C need to be specifically exposed to the scripting language, so usually people just write extra functions in mushcode rather than add them to the server itself.
13 Jul, 2010, ralgith wrote in the 11th comment:
Votes: 0
Idealiad said:
@ralgith, adding the function in the C code is not a bad idea in itself, but most programming in mux is done with the runtime scripting language (called mushcode or softcode). Functions in C need to be specifically exposed to the scripting language, so usually people just write extra functions in mushcode rather than add them to the server itself.


Cool, always nice to expand my knowledge.

I've always been a Circle user, but I've converted a lot of other people's code from Merc, Rom, Rot, and other code bases. However I've never dealt with any of the TinyMUD derivatives, so this is a learning experience for me as well as the OP.
13 Jul, 2010, ralgith wrote in the 12th comment:
Votes: 0
Ok, tweaked and updated more. Thanks go out to Jamdog of tbaMUD for his ideas and points… especially catching the fact that it doesn't work with multiple spaces between words!!
/*
* str_cew: Function to capitalize the first letter each word in a string.
* All other letters in the string are returned returned in lower case.
* Does not modify original string. Returns void.
*
* Written by Ulath of Caer Dubrin 12 July 2010
* Feature and Bugfix suggestions Jamdog of tbaMUD forums 13 July 2010
*/
void str_cew(char *argument, char *new_arg)
{
*new_arg = '\x0';

if (!argument || !new_arg) {
log("SYSERR: str_cew received a NULL pointer!");
return;
}

if (!*argument) {
log("SYSERR: str_cew received no argument!");
return;
}

/* CircleMUD function to strip leading spaces from the string */
skip_spaces(&argument);

*(new_arg++) = UPPER(*argument);
argument++;

while (*argument) {
if (isspace(*argument)) {
while (*argument && isspace(*argument)) { /* Loop here, so we can work with multiple spaces. Thanks Jamdog */
*(new_arg++) = *argument; /* Since this is a space, we don't need to use LOWER on it. Thanks Jamdog. */
argument++;
}
if (*argument != '\x0') {
*(new_arg++) = UPPER(*argument);
}
} else {
*(new_arg++) = LOWER(*argument);
}
if (*argument != '\x0')
argument++;
}

*new_arg = '\x0';

return;
}
13 Jul, 2010, Tyche wrote in the 13th comment:
Votes: 0
If you're feeling brave enough to modify your driver and recompile it…

In functions.cpp, add the following entry to "builtin_function_list" it's near the bottom of the file.
{"CAPSTRALL",     fun_capstrall,           1, 1,       1,         0, CA_PUBLIC},


Then somewhere above, maybe close to fun_capstr) add the following function:
static FUNCTION(fun_capstrall)
{
UNUSED_PARAMETER(executor);
UNUSED_PARAMETER(caller);
UNUSED_PARAMETER(enactor);
UNUSED_PARAMETER(nfargs);
UNUSED_PARAMETER(cargs);
UNUSED_PARAMETER(ncargs);

char *pString = fargs[0];
char *pBuffer = *bufc;
size_t nString = strlen(pString);
nString = safe_copy_buf(pString, nString, buff, bufc);

bool findblank = false;
// Find the first text character in (nString, pBuffer).
//
while (nString)
{
size_t nTokenLength0;
size_t nTokenLength1;
int iType = ANSI_lex(nString, pBuffer, &nTokenLength0, &nTokenLength1);
if (iType == TOKEN_TEXT_ANSI)
{
if (!findblank) {
*pBuffer = mux_toupper(*pBuffer);
findblank = true;
} else if (*pBuffer == ' ')
findblank = false;
}
pBuffer += nTokenLength0;
nString -= nTokenLength0;
}
}


This is untested. I have no idea if there are any other considerations.
P.S. I was looking at the TinuyMUX 2.6 code. Dunno if there are version dpendencies either.
13 Jul, 2010, Tyche wrote in the 14th comment:
Votes: 0
For vanilla C++, this:
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;

void cap_all_str( char *s )
{
size_t nchars = strlen(s);
bool findblank = false;
while (nchars) {
if (!findblank) {
*s = toupper(*s);
findblank = true;
} else if (*s == ' ')
findblank = false;
++s;
–nchars;
}
return;
}

int main(void) {
char test[] = "these are the times that try men's souls";
cout << test << endl;
cap_all_str(test);
cout << test << endl;
return 0;
}
14 Jul, 2010, ralgith wrote in the 15th comment:
Votes: 0
Tyche, your C++ code looks to have the same issue as my original C function did, it wont handle multiple spaces.
14 Jul, 2010, David Haley wrote in the 16th comment:
Votes: 0
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;

void cap_all_str(char *s)
{
bool skipping_blank = true;

while (*s) {
if (skipping_blank && *s != ' ') {
skipping_blank = false;
*s = toupper(*s);
}
else if (*s == ' ') {
skipping_blank = true;
}

s++;
}
return;
}

int main()
{
char test[] = " these are the times that try men's souls";
cout << test << endl;
cap_all_str(test);
cout << test << endl;
return 0;
}
$ g++ test.cpp
$ ./a.out
these are the times that try men's souls
These Are The Times That Try Men's Souls
$


This version also only iterates over the string once (by avoiding the initial strlen).
14 Jul, 2010, ralgith wrote in the 17th comment:
Votes: 0
Very nice.

I've uploaded a new file to the Code Repository here that contains the function I wrote for this thread, and 2 more string functions I wrote. Once it's approved feel free to download.
Its in the Diku/Circle/Snippiets section, but as I said its pretty generic other than skipspaces()
14 Jul, 2010, Tyche wrote in the 18th comment:
Votes: 0
ralgith said:
Tyche, your C++ code looks to have the same issue as my original C function did, it wont handle multiple spaces.


Quite right. It might also be good to handle other white space too…
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;

void cap_all_str( char *s )
{
size_t nchars = strlen(s);
bool findblank = false;
while (nchars) {
if (!findblank && !isspace(*s)) {
*s = toupper(*s);
findblank = true;
} else if (isspace(*s))
findblank = false;
++s;
–nchars;
}
return;
}

int main(void) {
char t1[] = "these are the times that try men's souls";
cout << t1 << endl;
cap_all_str(t1);
cout << t1 << endl;
char t2[] = " it was a pleasure to\tburn, \n\rto see things blackened and changed. ";
cout << t2 << endl;
cap_all_str(t2);
cout << t2 << endl;
return 0;
}


BTW, That MUX mod won't work at all on the new MUX 2.9 at all. The strings are now UTF-8.
18 Jul, 2010, Valo wrote in the 19th comment:
Votes: 0
Idealiad said:
Valo, did you add capstr_all as a @function? Without that calling it won't work.


Yes I did. It's even listed in the @list functions. Sorry it took a few days to get back to you on this.

Edit: I have gotten it to work with a think [capstr_all(test code)], but it doesn't wanna work in the code I posted before.
18 Jan, 2011, Valo wrote in the 20th comment:
Votes: 0
Update: I got it to work with the following code.

&fn_capstr_all #5=[iter(%0,capstr(##),switch(%1,,%B,%1),switch(%1,,%B,%1))]
0.0/20