User talk:ANSI Soderstrom/Misc useful functions

From Second Life Wiki
Jump to navigation Jump to search


printf

Your printf will have a problem if the text being inserted contains "%s". I'd recommend either splitting the input string into a list or copying the output into a new string so that it doesn't get the opportunity to chew on it's own tail. -- Strife (talk|contribs) 12:10, 14 May 2013 (PDT)

<lsl> // modify a string in ANSI-C style // returns a string with all replacements for "modifier".... based on the equivalent positions in the list-content string printf(string sentence, list insertation) {

   integer count = llGetListLength(insertation);
   if(count) {
       list modifiers = ["%s"];
       list split = llParseString2List(sentence, [], modifiers);
       integer last = llGetListLength(split) - 1;
       integer i = 0;
       integer k = -1;
       do {
           while(!~llListFindList(modifiers, llList2List(split, ++k, k))) {
               if(k == last) {//this is an error!
                   return (string)split;
               }
           }
           //string splitter = llList2String(split, k);
           //if (splitter == "%s")
           split = llListReplaceList(split, llList2List(split, i, i), k, k);
       } while(count > ++i);
       return (string)split;
   }
   return "Error, the insertation list is empty!\n(sentence: " + sentence + ")";

} </lsl>

Soderstrom's function got me thinking, but I find this version more useful. The text to be tailored can contain a number of specifically identified insertion points, the order not being important. Insertion points are identified as %0 to %9. Please don't complain that it'll fail if any insertion text includes a % ... I just won't script that possibility. Similarly I wouldn't script a null insertion list :) Omei Qunhua 06:43, 15 May 2013 (PDT)

<lsl> string CustomiseText(string sentence, list insertation) {

   integer i;
   integer match;
   while ( (match = llSubStringIndex(sentence, "%") ) != -1)
   {
       i = (integer) llGetSubString(sentence, match+1, match+1);
       sentence = llDeleteSubString(sentence, match, match +1);
       sentence = llInsertString(sentence, match, llList2String(insertation, i) );
   }
   return sentence;

}

string OwnerName;    // script will contain code to populate this
string WelcomeMsg = "Hello %0, welcome to this home owned by %1";   // Typically this text might come from a notecard
   llSay(0, CustomiseText(WelcomeMsg, [llDetectedName(0), OwnerName]) );
   

</lsl>

I considered adding that style of syntax (it's needed for printf parameters) but decided I was too lazy. As to why to I chose to stop recursion, it probably isn't an issue for user interfaces, but if you are using it on a back end for serialization and the user can inject some of their own data, you potentially have a leak. That aside, you really shouldn't allow it for your script, it will result in an infinite loop and if the text being inserted contains more than the minimum characters it will run out of memory. -- Strife (talk|contribs) 22:45, 18 May 2013 (PDT)

<lsl> CustomiseText("%0", ["%0"])//infinite loop CustomiseText("%0", ["%1", "%0"])//infinite loop CustomiseText("%0", ["%0!"])//eventual crash </lsl>

In retrospect recursion might be wanted as you could intentionally define a complex tree. What you don't want is looping. The following keeps you from looping. It assumes you have a replace_all function.

<lsl> string CustomiseText(string sentence, list insertations) {

   integer i = insertations != [];
   while (0 <= --i) {
       string replaces = "%" + i;
       string with = replace_all(llList2String(insertations, i), replaces, "");//hide the loop
       list next = [];
       integer j = 0;
       for (j < i; j++) {
           next += replace_all(llList2String(insertations, j), replaces, with);
       }
       insertations = next;
       sentence = replace_all(sentence, replaces, with);
   }
   return sentence;

} </lsl>