User:Void Singer/Functions
uParseEquation
- Parses a string equation and returns a formatted result
- Supports the following operations and proper order of operations:
- Parenthesis("(",")")
- Negation ("-")
- Exponentiation ("^")
- Division and Multiplication ("/", "*")
- Subtraction & Addition ("-", "+")
- Supports (Case insensitive) constant replacement:
- "e" (Euler's Number: 2.7182817)
- "pi" (Archimedes' Constant: 3.1415927)
- "phi" (Golden Ratio: 1.6180340)
- Supports implied multiplication of parenthesis and constants
- (2)3 == 2*3
- 2pi == 2*pi
- Supports Roots in the format of x^(1/y) (the "y" root of "x", where both are decimal numbers)
- Supports error detection:
- Unsuported characters
- Invalid/Missing Operators
- Divide by Zero
- Empty/Missing Parenthesis
- Ignores spaces
<lsl>string uParseEquation( string vStrTmp ){
list lst_OPS = ["+", "-", "*", "/", "^"]; list vLstEqn; list vLstTmp; list vLstSwp; integer vIdxFnd; integer vIdxBgn; integer vIdxEnd; integer vIntCnt; integer vIntErr; vStrTmp = llToLower( "(" + vStrTmp + ")" ); vLstTmp = llParseString2List( vStrTmp, lst_OPS + ["pi", "phi"], [] ); vLstTmp = llParseString2List( (string)vLstTmp, ["0", "1", "2", "3", "4", "5", "6", "7"], [] ); vLstTmp = llParseString2List( (string)vLstTmp, ["8", "9", ".", "e", "(", ")", " ", "="], [] ); if (vLstTmp != []){ jump Err0; } vStrTmp = llDumpList2String( llParseStringKeepNulls( vStrTmp, ["e"], [] ), "(2.7182817)" ); vStrTmp = llDumpList2String( llParseStringKeepNulls( vStrTmp, ["pi"], [] ), "(3.1415927)" ); vStrTmp = llDumpList2String( llParseStringKeepNulls( vStrTmp, ["phi"], [] ), "(1.6180340)" ); vLstEqn = llParseString2List( vStrTmp, [" ", "="], lst_OPS + ["(", ")"] ); while (~(vIdxEnd = vIdxBgn = llListFindList( vLstEqn, (list)")" ))){ while (llList2String( vLstEqn, vIdxBgn ) != "(" && ~(--vIdxBgn)); if (~vIdxBgn){ if (vIdxEnd - vIdxBgn > 1){ if (~llListFindList( lst_OPS, (list)llList2String( vLstTmp = llList2List( vLstEqn, -~vIdxBgn, ~-vIdxEnd ), 0xFFFFFFFF ) )){ jump Err1; } if (~(vIdxFnd = llListFindList( lst_OPS, (list)llList2String( vLstTmp, 0 ) ))){ if (1 == vIdxFnd && !~llListFindList( lst_OPS, (list)llList2String( vLstTmp, 1 ) )){ vLstTmp = llListReplaceList( vLstTmp, (list)(-llList2Float( vLstTmp, 1 )), 0, 1 ); }else{ jump Err2; } } vIntCnt = ([] != vLstTmp); while(++vIntCnt < 0){ if (~llListFindList( lst_OPS, (list)llList2String( vLstTmp, vIntCnt) )){ if (~(vIdxFnd = llListFindList( lst_OPS, (list)llList2String( vLstTmp, ++vIntCnt ) ))){ if (1 == vIdxFnd && !~llListFindList( lst_OPS, (list)llList2String( vLstTmp, -~vIntCnt) )){ vLstTmp = llListReplaceList( vLstTmp, (list)(-llList2Float( vLstTmp, vIntCnt )), vIntCnt, -~vIntCnt ); --vIntCnt; }else{ jump Err3; } } }else{ jump Err4; } } vIntCnt = 4; do{ while (~(vIdxFnd = llListFindList( vLstTmp, (list)llList2String( lst_OPS, vIntCnt ) ))){ if (1 & vIntCnt){ if (2 & vIntCnt){ if (llList2String( vLstTmp, -~vIdxFnd )){ vLstSwp = ["*", 1 / llList2Float( vLstTmp, -~vIdxFnd )]; }else{ jump Err5; } }else{ vLstSwp = ["+", -llList2Float( vLstTmp, -~vIdxFnd )]; } }else{ if (vIntCnt){ if (4 & vIntCnt){ vLstSwp = (list)llPow( llList2Float( vLstTmp, ~-vIdxFnd ), llList2Float( vLstTmp, -~vIdxFnd ) ); }else{ vLstSwp = (list)( llList2Float( vLstTmp, ~-vIdxFnd ) * llList2Float( vLstTmp, -~vIdxFnd ) ); } }else{ vLstSwp = (list)( llList2Float( vLstTmp, ~-vIdxFnd ) + llList2Float( vLstTmp, -~vIdxFnd ) ); } } vLstTmp = llListReplaceList( vLstTmp, vLstSwp, vIdxFnd - !(1 & vIntCnt), -~vIdxFnd ); } }while (~(--vIntCnt)); vLstEqn = llListReplaceList( vLstEqn, vLstTmp, vIdxBgn, vIdxEnd ); }else{ jump Err6; } if (!~llListFindList( lst_OPS + [")", ""], (list)llList2String( vLstEqn, -~vIdxBgn ) )){ vLstEqn = llListInsertList( vLstEqn, (list)"*", -~vIdxBgn ); } if (vIdxBgn){ if (!~llListFindList( lst_OPS + (list)"(", (list)llList2String( vLstEqn, ~-vIdxBgn ) )){ vLstEqn = llListInsertList( vLstEqn, (list)"*", vIdxBgn ); } } }else{ jump Err7; } } if (~llListFindList( vLstEqn, (list)"(" )){ jump Err8; } if (vLstEqn != ["="]){ jump Err9; } if ((integer)vStrTmp == (float)(vStrTmp = llList2String( vLstEqn, 0 ))){ vStrTmp = (string)((integer)vStrTmp); }else{ vIntCnt = llStringLength( vStrTmp ); while ("0" == llGetSubString( vStrTmp, --vIntCnt, vIntCnt )); vStrTmp = llGetSubString( vStrTmp, 0, vIntCnt ); } jump Errors; @Err9; ++vIntErr; @Err7; @Err8; ++vIntErr; @Err6; ++vIntErr; @Err5; ++vIntErr; @Err4; ++vIntErr; @Err3; ++vIntErr; @Err1; @Err2; ++vIntErr; @Err0; vStrTmp = "Error: " + llList2String( ["Unsupported Character(s)", "Outside Operator(s)", "Stacked Operator(s)", "Missing Operator(s)", "Divide By Zero", "Empty Parenthesis", "Missing Parenthesis", "Catastrophic Failure"], vIntErr ) + "\n" + llDumpList2String( vLstEqn, " " ) + "\n" + vStrTmp; @Errors; return vStrTmp;
} /*//-- License Text --//*/ /*// Free to copy, use, modify, distribute, or sell, with attribution. //*/ /*// (C)2010 (CC-BY) [ http://creativecommons.org/licenses/by/3.0 ] //*/ /*// Void Singer [ https://wiki.secondlife.com/wiki/User:Void_Singer ] //*/ /*// All usages must contain a plain text copy of the previous 2 lines. //*/ /*//-- --//*/</lsl>
uListFindListLast
- This function is a companion to llListFindList.
- designed for string data only.
- Can not handle empty string elements
- Returns 0 if list test is empty, but list source is not; just like llListFindList
- SPECIAL NOTE: data should NOT contain the "•" character(alt+7)... please use a different character if this one is expected.
Get Last Index of List Test in List Source <lsl>integer uListFindListLast( list vLstSrc, list vLstTst ){ integer vIdxFnd = (vLstSrc != (vLstTst + llParseString2List( llList2String( llParseStringKeepNulls( llDumpList2String( vLstSrc, "•" ), (list)llDumpList2String( vLstTst, "•" ), [] ), 0xFFFFFFFF ), ["•"], [] )));
return (vIdxFnduListFindAny*
- These functions are companions to llListFindList.
- designed for string data only.
- Can not handle empty string elements
- SPECIAL NOTE: data should NOT contain the "•" character(alt+7)... please use a different character if this one is expected.
Get the First index in List Source of Any element in List Test
<lsl>integer uListFindAnyFirst( list vLstSrc, list vLstTst ){ return ~(~( llParseString2List( llList2String( llParseStringKeepNulls( llDumpList2String( vLstSrc, "•" ), vLstTst, [] ), 0 ), ["•"], [] ) != []) % ~(vLstSrc != [])); } /*//-- Anti-License Text --//*/ /*// Contributed Freely to the Public Domain without limitation. //*/ /*// 2012 (CC0) [ http://creativecommons.org/publicdomain/zero/1.0 ] //*/ /*// Void Singer [ https://wiki.secondlife.com/wiki/User:Void_Singer ] //*/ /*//-- --//*/</lsl>
Get the Last index in List Source of Any element in List Test<lsl>integer uListFindAnyLast( list vLstSrc, list vLstTst ){ return ~( llParseString2List( llList2String( llParseStringKeepNulls( llDumpList2String( vLstSrc, "•" ), vLstTst, [] ), 0xFFFFFFFF ), ["•"], [] ) != vLstSrc); } /*//-- Anti-License Text --//*/ /*// Contributed Freely to the Public Domain without limitation. //*/ /*// 2012 (CC0) [ http://creativecommons.org/publicdomain/zero/1.0 ] //*/ /*// Void Singer [ https://wiki.secondlife.com/wiki/User:Void_Singer ] //*/ /*//-- --//*/</lsl>
uDlgBtnPagList
- Effectively allows more than 12 button on a dialog by breaking them up into pages and adding page change buttons as needed
- Corrects the button order to [left to right, top to bottom] (AKA English Order]
- Automatically wraps around from the last and first pages
- Supports up to 22 pages safely (220 items in the list)
- Supports multiple simultaneous users
- Support Re-menuing
- Requires the button text(s) to be in a global list named gLstMnu (which you can fill however you like)
- this function does NOT check that button text is valid (0 < button_text_length < 25), that's your job
- Individual button texts cannot' start with a non-breaking space (alt+255).
<lsl>list uDlgBtnPagLst( integer vIdxPag ){
list vLstRtn; if ((gLstMnu != []) > 12){ //-- we have more than one possible page integer vIntTtl = -~((~([] != gLstMnu)) / 10); //-- Total possible pages integer vIdxBgn = (vIdxPag = (vIntTtl + vIdxPag) % vIntTtl) * 10; //-- first menu index string vStrPag = llGetSubString( " ", 21 - vIdxPag, 21 ); //-- encode page number as spaces //-- get ten (or less for the last page) entries from the list and insert back/fwd buttons vLstRtn = llListInsertList( llList2List( gLstMnu, vIdxBgn, vIdxBgn + 9 ), (list)(" «" + vStrPag), 0xFFFFFFFF ) + (list)(" »" + vStrPag); }else{ //-- we only have 1 page vLstRtn = gLstMnu; //-- just use the list as is } return //-- fix the order for [L2R,T2B] and send it out llList2List( vLstRtn, -3, -1 ) + llList2List( vLstRtn, -6, -4 ) + llList2List( vLstRtn, -9, -7 ) + llList2List( vLstRtn, -12, -10 );
} /*//-- Anti-License Text --//*/ /*// Contributed Freely to the Public Domain without limitation. //*/ /*// 2012 (CC0) [ http://creativecommons.org/publicdomain/zero/1.0 ] //*/ /*// Void Singer [ https://wiki.secondlife.com/wiki/User:Void_Singer ] //*/ /*//-- --//*/</lsl>
How to incorporate into llDialog calls:<lsl>llDialog( Target_avatar_key, text_for_dialog_header, uDlgBtnLst( 0 ), chat_channel_to_use );</lsl>
How to detect and handle responses:<lsl> listen( integer vIntChn, string vStrNom, key vKeySpk, string vStrMsg ){
if (!llSubStringIndex( vStrMsg, " " )){ //-- detects (hidden) leading non-breaking space of page change buttons llDialog( vKeySpk, "your dialog text goes here", uDlgBtnLst( llStringLength( vStrMsg ) + llSubStringIndex( vStrMsg, "»" ) - 2 ), vIntChn ); }else{ //-- button was not a page button, your code goes here, //-- use (llListFindList( gLstMnu, (list)vStrMsg ) / 10) for remenu command if present } }</lsl>