ZLib -- Zarqon's useful function library

Winterbay

Active member
There seems to be a bug somewhere. The last few days when I've had scripts indicate that they need to be updated the following has happened (as today with zlib). Note that this is with zlib v.22, only I changed the 22 to 21 in the check_version-call for the sake of testing (to see that it wasn't one of my modifications to the old one that did it):

Code:
> zlib vars

Checking for updates (running ZLib ver. : 21)...
_version_zlib => : 22
New Version of ZLib Available: : 22
Group 1 requested, but pattern only has 0 groups (zlib.ash, line 164)

This aborts all script-running.

I have no idea what is causing this effect.
 

Raven434

Member
Same as Winterbay. At a different place though.

Never mind. r8945 was downloaded and I am *not* having any issues.
 
Last edited:

Winterbay

Active member
You really need to upgrade your Mafia version. That problem should go away after r8916 since it is due to zlib now using ** instead of ^ for power-calculations.
(rnum() is the function that line is in)
r8915:
Code:
> ash import <zlib.ash>; string test = rnum(12.2548,2); print(test)

Value expected (zlib.ash, line 90)
Returned: void

r8916:
Code:
> ash import <zlib.ash>; string test = rnum(12.2548,2); print(test)

_version_zlib => : 22
12.25
Returned: void
 

zarqon

Well-known member
Which of these should I use to match the "1234" in "[requires revision 1234]"?

create_matcher("\[requires revision (.+?)\]",page);

create_matcher("\\[requires revision (.+?)\\]",page);


It's currently the first one.
 

StDoodle

Minion
The latter; anything with meaning in regex that needs to be matched as shown (parentheses, brackets, etc.) should be double-escaped in the matcher. Which is why my check_version()'s use (bbcode) size instead of such fancy bracketing. ;)
 

StDoodle

Minion
Ugh, I hate double-posting, but this is a completely separate idea...

I'd like to request a feature that is the #1 reason why I keep using my own version of check_version() as opposed to yours: could you overload check_version() to accept a float as the script version, and only give the update nag if the found version is higher? Updating my script version is something I tend to do as soon as I post a version, to make sure I don't forget when I post a new version again. However, this means I get an update notice every day, since the two versions don't match. ;)
 

zarqon

Well-known member
Okay, I've made more updates. Rather than annoy everyone, I've added these new features without bumping the version number. If you want them, re-download from the first post. Since they're non-essential changes (currently), it's up to you.

Changes:
  • Removed the function list from the first post, instead linking to ZLib's fairly new Wiki page. Edited first post accordingly.
  • Escaped the escaping in that regex.
  • Bumped verbosity in eval()'s print statement to 10, since it's something you would really only want to see when debugging.
  • Added the ability for normalized() to normalize comma-delimited lists of any basic type. Specify "list of type" for the second parameter to make this happen. For example:
PHP:
normalized("panda, cove, giant","list of location")

// returns "Pandamonium Slums, Pirate Cove, Giant's Castle"

normalized("tick, dancing, wegjewrgjophg","list of familiar")

// returns "Ghost Pickle on a Stick, Dancing Frog, none"
 

Theraze

Active member
Any chance we could get hola's shiny equals function added to zlib?
But if I break it, you couldn't implement your own string.equals. :D

PHP:
boolean equals( string arg1, string arg2 )
{
return arg1.length() == arg2.length() && arg1.contains_text(arg2);
}
 

CRennings

New member
Hey, I've spent several days trying to figure out how to fix a problem myself with no luck, and have read back a few pages hoping I'd just missed an update, but to no avail. Any time any script calls Zlib I get the error message Cannot apply operator ^ to ( n * 10.0 ) (float) and place (int) (zlib.ash, line 71). I've checked that i have the most up to date versions of all my scripts and the most recent hourly build, nothing. I'm going to guess someone else has had this problem, but some help would be appreciated.

Edit: I've found that deleting line 71 has brought functionality back to the scripts that I use, but it feels as though I've begun tampering with forces I don't begin to comprehend, and will soon break the internet in some complex Rube-Golbergian fashion.
 
Last edited:

StDoodle

Minion
CRennings, that doesn't match what's in the current version of the script on line 71. Any chance you've got an older version of the script at a higher directory level in /scripts than the newest version?
 

StDoodle

Minion
Zarqon! I know I'm not the first to request the ability to compare versions and suppress the upgrade notification if for some reason (usually, your own script, in testing) the local version is higher than the forum version. Now you can! Below is a function to do so (note: I will eventually be putting up my own library script, likely; but if you include this function in zlib I'll leave it out, as oddly enough, my library requires zlib.ash; I'm just too happy with vprint!).

Of course, no such function can handle absolutely every situation, but this one should be more than flexible enough for all of the mafia scripts I've seen. (Note: contains regex, don't look too closely if you want to avoid being "bitten.")

PHP:
string compare_versions(string verA, string verB) {
    matcher m; string numA; string numB; string otherA; string otherB;
    m = create_matcher("\\d+(?:\\.\\d+|\\s\\d+|:\\d+|-\\d+|_\\d+)*", verA);
    if (m.find()) { numA = m.group(); otherA = replace_first(m, " "); } else return "error";
    m = create_matcher("\\d+(?:\\.\\d+|\\s\\d+|:\\d+|-\\d+|_\\d+)*", verB);
    if (m.find()) { numB= m.group(); otherB = replace_first(m, " "); } else return "error";
    string [int] splitA; string [int] splitB; int secA; int secB;
    splitA = split_string(numA, "(?:\\.|\\s|:|-|_)");
    splitB = split_string(numB, "(?:\\.|\\s|:|-|_)");
    for i from 0 to max(count(splitA) - 1,count(splitB) - 1) {
        if (i > count(splitA) - 1) secA = 0; else secA = splitA[i].to_int();
        if (i > count(splitB) - 1) secB = 0; else secB = splitB[i].to_int();
        if (secA != secB) return (secA > secB) ? verA: verB;
    }
    if (otherA == otherB) return "";
    int statusA; int statusB; //0-4 for d,a,b,rc,final
    switch {
        case (find(create_matcher(
                        "\\b(?:\\.|\\s|:|-|_)?d(?:(?:ev)?elopment)?(?:\\.|\\s|:|-|_)?\\b", otherA))):
            statusA = 0;
            break;
        case (find(create_matcher(
                        "\\b(?:\\.|\\s|:|-|_)?a(?:lpha)?(?:\\.|\\s|:|-|_)?\\b", otherA))):
            statusA = 1;
            break;
        case (find(create_matcher(
                        "\\b(?:\\.|\\s|:|-|_)?b(?:eta)?(?:\\.|\\s|:|-|_)?\\b", otherA))):
            statusA = 2;
            break;
        case (find(create_matcher(
                        "\\b(?:\\.|\\s|:|-|_)?r(?:c|elease candidate)(?:\\.|\\s|:|-|_)?\\b", otherA))):
            statusA = 3;
            break;
        default: statusA = 4;
    }
    switch {
        case (find(create_matcher(
                        "\\b(?:\\.|\\s|:|-|_)?d(?:(?:ev)?elopment)?(?:\\.|\\s|:|-|_)?\\b", otherB))):
            statusB = 0;
            break;
        case (find(create_matcher(
                        "\\b(?:\\.|\\s|:|-|_)?a(?:lpha)?(?:\\.|\\s|:|-|_)?\\b", otherB))):
            statusB = 1;
            break;
        case (find(create_matcher(
                        "\\b(?:\\.|\\s|:|-|_)?b(?:eta)?(?:\\.|\\s|:|-|_)?\\b", otherB))):
            statusB = 2;
            break;
        case (find(create_matcher(
                        "\\b(?:\\.|\\s|:|-|_)?r(?:c|elease candidate)(?:\\.|\\s|:|-|_)?\\b)", otherB))):
            statusB = 3;
            break;
        default: statusB = 4;
    }
    
    if (statusA != statusB) return (statusA > statusB) ? verA : verB;
    int otherNumA = 0; int otherNumB = 0;
    m = create_matcher("\\d+", otherA);
    if (m.find()) otherNumA = m.group().to_int();
    m = create_matcher("\\d+", otherB);
    if (m.find()) otherNumB = m.group().to_int();
    return (otherNumA == otherNumB) ? "" : (otherNumA > otherNumB) ? verA : verB;
}

Some comments on operation:

Code:
Fairly robust comparisson of two strings as software revisions
returns the HIGHER or the two, or "" if they are equal

First, all numbers are compared (numerically, not as strings)
Possible separators are:
    . (space) - : _ (nothing: single number)
    Only a single char. of the above between numbers will be recognized between each set of number(s)
    The first numbers in your string will be matched as the most "important" part of your versioning
        don't start your string with "rc1" then follow with the major/minor/bug or alt. numbering
        if you use sep. numbering for dev/alpha/beta/rc/(final), it must FOLLOW the other versioning
    At each "level" from left to right, any numbers present in one string and not the other will have 0 substituted
        ie comparing 14.2 to 14.2.1 compares as 14.2.0 to 14.2.1

If version numbers as above are equal, next look for status and compare
The following are looked for in the strings (either the full word OR abbreviation, given in parentheses)
Note that if none are found, "final" is assumed

dev OR development (d) < alpha (a) < beta(b) < release candidate (rc) < final (no suffix)

Any leftover text is ignored: feel free to use "v" or "r" (but not rc!) in your version strings
        you can't use a single d, a, b (or "rc") in the rest of the string, or it will be treated as a status
        by single I mean by itself, with blank or version at the boundaries
            ie "u b ready? v1.0.2" would parse the "b" as "beta"
            ie "this is really cool, yah? 12-2-0_dev" will properly see "dev" and not fire on the "r" in "really"

After the above checks, it will search for any remaining consecutive numbers that weren't part of the first number / separator sect.
    if either is not found, it is assumed to be 0
    these remaining numbers are compared, highest being newest
    
If all of the above has been checked and evaluates as equal, "" is returned

If matching fails (for example, the function can't parse at least one number string from both versions, "error" is returned
    obviously, this means it would muck things up to use "error" in any version name passed to this function

Some Examples:

Code:
compare_revisions("1.0", "0.9") -> "1.0"
compare_revisions("1.0.0", "1.0.0dev") -> "1.0.0"
compare_revisions("14.2.8", "v14.2.9") -> "v14.2.9"
compare_revisions("rev11.0.1", "12 dev") -> "12 dev"
compare_revisions("13.0", "12.8.4.6.99.2 release candidate") -> "13.0"
compare_revisions("11.1d", "11.1_d3") -> "11.1_d3"
compare_revisions("beta 3 1.1.1", "1.2") -> "beta 3 1.1"
    this is because the 3 is matched first, and taken as the 'major' revision
    a numbered status currently needs to follow the main numbering
compare_revisions("1.5", "1.41") -> "1.41"
    you need to use a separator between all levels of differentiation;
    ".41" is treated as 41, which is > 5
    you CAN use a different separator for a normally-unused bugfix level
compare_revisions("1.4", "1.4:2") -> "1.4:2"

If this is added to zlib's check_version(), it would probably (almost certainly) be best to overload check_version() so that it can either be called as it is currently, or with an additional boolean representing whether versions should be compared. But that's your call, of course, of course.

Edit: Uses ternary syntax in two places, yay!
Edit again: fix mistakes noticed by hee3, change stuff so that now you can use words with the status letters and they won't flag the status unless the letters are by themselves (maybe?).
 
Last edited:

Theraze

Active member
Well, you could do the last 2 lines like this...
PHP:
return (statusA == statusB) ? "" : (statusA > statusB) ? verA : verB;
Basically, if the two are the same, return "" (why not return either one?), else if A > B, return A, else return B.

Edit: For that matter, it works much simpler in cases of the above returns...
PHP:
if (secA != secB) return (secA > secB) ? verA: verB;

Eh, I just like terniaries too much, I think. :D
 
Last edited:

StDoodle

Minion
True enough! Mostly, I just failed to optimize such things after taking out my various print() calls I used while debugging. ;)

Similarly, earlier on in the for loop the last two lines could be converted to "if (secA != secB) return (secA > secB) ? verA : verB;"

Edit to add:

As to:
why not return either one?

The reason is that the script is currently set up to return the highest version, not set up to ask whether A is higher than B or vice-versa. Either would likely work, but the latter would probably require an abort() to be used if versions couldn't be parsed, as there isn't a third possibility for a boolean, and asking a yes-no question that gives something other than a boolean return value just doesn't sit well with me. ;) Of course, since this would be used in check_version(), an abort() would be bad.
 
Last edited:

StDoodle

Minion
Note: I edited in just a teensy bit more (you can now have numbered status, ie dev1, rc9), but only integers are checked at that point. Also added some examples, and fixed the spelling of "candidate."

Edit to add: the bad news is, that Bale at least is using a versioning system incompatible with this script. My script says "v1.41" is higher than "v1.5", and would require a separator between the 4 & 1 for it to show as lower. :( That's what happens when a non-programmer writes something like this, I guess... :(
 
Last edited:

heeheehee

Developer
Staff member
fixed the spelling of "candidate."

Missed one, I think.
PHP:
        case (find(create_matcher("release cantidate",otherA))): statusA = 3; break;

Overall very nice, though. A few issues, though:
PHP:
b[eta]?
will catch things like "ba" but not "beta".

While we're at it,
PHP:
case (find(create_matcher("d[ev]?[elopment]?",otherA))): statusA = 0; break;
can use "dev(elopment)?". Similarly,
PHP:
        case (find(create_matcher("rc",otherB))): statusB = 3; break;
        case (find(create_matcher("release candidate",otherB))): statusB = 3; break;
could just use "(rc|release candidate)".

I'm not totally sure what the TODO really means.
 

StDoodle

Minion
Oh GAH! Yeah, those square brackets were all sup'd to be non-capturing groups, I don't know what happened to my head. Ugh.

The reason "rc" and "release candidate" are sep. is I was originally going to try to put in the added stuff that goes along with my "TODO" note, and thought there was a chance I'd need them separate, but then I couldn't wrap my head around how exactly to handle it.

For reference, the "TODO" refers to my desire to not capture any strings that arbitrarily include the letters being matched. However, because of the fact that I wanted the status strings to be matchable if they were anywhere in the string, butted-up against other letters or the regular version number portion or whatever, it got rather headachey.

Also, thanks for pointing those out!
 

heeheehee

Developer
Staff member
Oh, one more thing I forgot to point out with the whole "d(?:ev)?(?:evelopment)?" matcher -- that'll match "d" as well as "dev" and "development". And "devevelopment".
 
Top