mIRC Home    About    Download    Register    News    Help

Print Thread
#183794 22/08/07 05:31 PM
Joined: Jun 2007
Posts: 35
Ameglian cow
OP Offline
Ameglian cow
Joined: Jun 2007
Posts: 35
I have no idea what's causing this, but the /continue command (in the third "paragraph") seems to /halt execution rather than jump to the top of the main loop.

This only happens when /continue is reached, which needs multi-word input e.g. /rc a b

With the above input, one can verify this by adding /echo -a %i , %len just before the /continue, and if (%i == %len) echo -a test as the first command of the main loop. This prints "3 , 3" but not "test".

I tried adding { } around the internal loop's step, which got me a different, but still abnormal, result. eek

Code:
; /rc <text> - Colors each character in a random color, but
; not the same one twice in a row. UTF-8 text is supported.
; Requires $utf8len().
rc {
  var %res, %spc, %lastcol
  var %len = $len($$1-), %i = 1

  while (%i <= %len) {
    var %chr = $mid($1-,%i,4)
    var %chrlen = $utf8len(%chr)
    %chr = $left(%chr, %chrlen)

    if (%chr == $chr(32)) {
      %spc = $true | inc %i | continue
    }

    var %col = %lastcol
    while (%col == %lastcol) %col = $rand(2,14)
    %lastcol = %col | if (%col < 10) %col = 0 $+ %col
    %col = $chr(3) $+ %col

    if (%spc) {
      %res = $+(%res,$chr(3)) $+(%col,%chr)
      %spc = $false
    }
    else %res = $+(%res,%col,%chr)

    inc %i %chrlen
  }

  say %res $+ $chr(3)
}


; $utf8len(buf) - Returns the size of the UTF-8 character
; started at the first byte of "buf". Only the first four
; bytes of "buf" make any difference. Returns 1 on error.
utf8len {
  if ($asc($1) < 128) return 1
  var %res = 1

  if (($v1 >= 194) && ($v1 <= 223)) %res = 2
  elseif (($v1 >= 224) && ($v1 <= 239)) %res = 3
  elseif (($v1 >= 240) && ($v1 <= 243)) %res = 4

  ; validate the other bytes
  var %i = 2
  while (%i <= %res) {
    if (($asc($mid($1,%i,1)) < 128) || ($v1 > 191)) {
      return 1
    }
    inc %i
  }

  return %res
}

Last edited by alephresh; 22/08/07 07:40 PM.

Desired: right alignment of text; consecutive spaces in /command args; Ctrl+A in custom dialogs.
Joined: Oct 2003
Posts: 313
S
Fjord artisan
Offline
Fjord artisan
S
Joined: Oct 2003
Posts: 313
I think I have pared the code down to something that points to where the problem is:

(Fragment 1)
Code:
alias conttest {
  var %len = 3
  var %i = 1

  while (%i <= %len) {
    echo -a IN
    if (%i == 2) {
      echo -a CONT
      inc %i
      continue
    }
    echo -a MID

    inc %i

    echo -a OUT
  }
}


I get - as expected:
Code:
IN
MID
OUT
IN
CONT
IN
MID
OUT


If I change the echo -a MID line to:
(Fragment 2)
Code:
    echo -a MID
    var %n = 2
    while (%n) dec %n


I now get:
Code:
IN
MID
OUT
IN
CONT

(the same results that aleph's code appears to give)

Now if I replace the
Code:
while (%n) dec %n

line with:
(Fragment 3)
Code:
    while (%n) { dec %n } 


I get:
Code:
IN
MID
OUT
IN
CONT
OUT


Note that it jumps from the continue to the end of the while loop now.

And finally, if I change that to:
(Fragment 4)
Code:
    
while (%n) {
  dec %n 
} 

(on multiple lines), I get:

Code:
IN
MID
OUT
IN
CONT
IN
MID
OUT


- the same, expected results as above.

So - is this some nuance on the multiple while command problem?



Last edited by Sais; 23/08/07 11:10 PM.

Sais
Joined: Jun 2007
Posts: 35
Ameglian cow
OP Offline
Ameglian cow
Joined: Jun 2007
Posts: 35
Nice work, Sais. smile

I'm going to try to show this example in a visual way. (I had to use some dirty invisible-text hack to get this working with indention.)

The blue bit is what's being changed between snippets.
The red bit is where the /continue jumps to. (I ran a few more tests to find the exact spot.)

I'll go in reverse order to Sais's post, and start with the normal-behavior version:


alias conttest {
__var %len = 3
__var %i = 1

__while (%i <= %len) {

____if (%i == 2) {
______inc %i
______continue
____}

____var %n = 2
____while (%n) {
[color:white]______
dec %n
____}[/color]

____inc %i

__}

}



Now the version with a single-line inner loop, but with { }. Notice how the arbitrary change of the inner loop makes /continue jump to the beginning of the inner loop instead of the main loop:


alias conttest {
__var %len = 3
__var %i = 1

__while (%i <= %len) {

____if (%i == 2) {
______inc %i
______continue
____}

____var %n = 2
____while (%n) [color:red]{ dec %n }[/color]

____inc %i

__}

}



And finally, same as above but without the { }. This time /continue stops script execution altogether (not /return, /halt):


alias conttest {
__var %len = 3
__var %i = 1

__while (%i <= %len) {

____if (%i == 2) {
______inc %i
______continue
____}

____var %n = 2
____while (%n) dec %n

____inc %i

__}

}


Last edited by alephresh; 24/08/07 12:02 AM.

Desired: right alignment of text; consecutive spaces in /command args; Ctrl+A in custom dialogs.
Joined: Dec 2002
Posts: 5,420
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,420
Thanks this should be fixed for the next version.

Joined: Jan 2004
Posts: 162
R
RRX Offline
Vogon poet
Offline
Vogon poet
R
Joined: Jan 2004
Posts: 162
This made me remember a problem I had to workaround in the past, in the next alias:
Code:
; +++ CHANNELLIST / GET IRC STATS
; Input: $1 = network (optional)
; Output:
; $1 = total nets $2 = total chans $3 = total users
; $4 = amount Serve channels with USERDATA ON $5 = amount users on these channels
; $6 = amount of $4 with SCAN enabled $7 = amount users on these channels
; NOTE: do not put the level 3 loops on one line, it starts skipping last channel
alias SC_ChannelList_GetIRCStats {
  SC_dl SC_ChannelList_GetIRCStats $1-
  var %t = $SC_ts, %a = $asc(%t), %net = $1, %htotal = $SC_rh, %hud = $SC_rh, %hscan = $SC_rh, %4 = $chr(44)
  var %total1 = $scon(0), %i1 = 1, %totalnet = 0, %totalchan = 0, %totalchanud = 0, %totalchanscan = 0
  while (%i1 <= %total1) {
    var %neti = $hget(SC_H,$+(Server,%4,$scon(%i1).cid)) | if (%neti == $null) { inc %i1 | continue }
    if (%net != $null) && (%neti != %net) { inc %i1 | continue }
    scid $scon(%i1).cid | if ($status != connected) { inc %i1 | continue }
    inc %totalnet | var %total2 = $comchan($me,0), %i2 = 1
    while (%i2 <= %total2) {
      var %chan = $comchan($me,%i2) | tokenize %a $SC_ChannelList_Get(%neti,%chan,USERDATA,SCAN)
      if ($1 == NOTFOUND) { inc %i2 | continue }
      inc %totalchan | var %total3 = $nick(%chan,0), %i3 = 1
      while (%i3 <= %total3) {
        hadd %htotal $+(%neti,%t,$nick(%chan,%i3))
        inc %i3
      }
      if ($1 != ON) { inc %i2 | continue }
      inc %totalchanud | var %i3 = 1
      while (%i3 <= %total3) {
        hadd %hud $+(%neti,%t,$nick(%chan,%i3))
        inc %i3
      }
      if ($2 != ON) { inc %i2 | continue }
      inc %totalchanscan | var %i3 = 1
      while (%i3 <= %total3) { 
        hadd %hscan $+(%neti,%t,$nick(%chan,%i3))
        inc %i3 
      }
      inc %i2
    }
    inc %i1
  }
  var %user = $hget(%htotal,0).item, %userud = $hget(%hud,0).item, %userscan = $hget(%hscan,0).item
  hfree %htotal | hfree %hud | hfree %hscan | return %totalnet %totalchan %user %totalchanud %userud %totalchanscan %userscan
}

I have the habit of putting the code for a single loop on one line if its very short.
So initially those 3 level 3 loops looked like:
Code:
while (%i3 <= %total3) { hadd %htotal | $+(%neti,%t,$nick(%chan,%i3)) | inc %i3 }

But after some time I discovered the returned numbers were wrong.
It seemed to somehow skip the last iteration of the level 2 loop.
I discovered that, to make it correct, I had to spread the code out on more lines like this:
Code:
while (%i3 <= %total3) {
 hadd %htotal $+(%neti,%t,$nick(%chan,%i3))
 inc %i3
}

I just tried to write standalone reproduction code but my first attempts failed so I just made some test runs to be able to give some more info, by trying various combinations of single line level 3 loops:

This is the output when all level 3 loops have their code spreaded out on more lines:
Nets:3 Chans:19 Users:382 UDchans:3 UDusers:@124H124/127

These are the testruns, the amount Nets and Chans surely remained the same, it's possible User counts changed while testing because it was real sitation on IRC:
ScanChans:2 ScanUsers:117
i3 loop 1 on 1 line:
Nets:3 Chans:18 Users:345 UDchans:3 UDusers:@123H123/126 ScanChans:2 ScanUsers:116
i3 loop 2 on 1 line:
Nets:3 Chans:14 Users:222 UDchans:2 UDusers:@123H123/12 ScanChans:1 ScanUsers:2
i3 loop 3 on 1 line:
Nets:3 Chans:13 Users:220 UDchans:2 UDusers:@123H123/12 ScanChans:1 ScanUsers:2
i3 loops 1+2 on 1 line:
Nets:3 Chans:14 Users:165 UDchans:2 UDusers:@123H123/12 ScanChans:1 ScanUsers:2
i3 loops 2+3 on 1 line:
Nets:3 Chans:12 Users:166 UDchans:1 UDusers:@123H123/2 ScanChans:1 ScanUsers:2
i3 loops 1+2+3 on 1 line:
Nets:3 Chans:12 Users:190 UDchans:1 UDusers:@123H123/2 ScanChans:1 ScanUsers:2

I don't know if the problem here is the same one as from this topic (so also 'should be fixed for the next release').

Last edited by RRX; 25/08/07 04:02 AM.

Link Copied to Clipboard