egghelp.org community Forum Index
[ egghelp.org home | forum home ]
egghelp.org community
Discussion of eggdrop bots, shell accounts and tcl scripts.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

syntax checking of user input on a public trigger
Goto page 1, 2  Next
 
Post new topic   Reply to topic    egghelp.org community Forum Index -> Script Requests
View previous topic :: View next topic  
Author Message
LoKii
Voice


Joined: 21 Oct 2009
Posts: 34

PostPosted: Wed Mar 13, 2013 7:11 am    Post subject: syntax checking of user input on a public trigger Reply with quote

Hi everyone.

Got something new here that is doing my head in.

I made a small script, where as the trigger is based on a few specific types of letters/numbers.

an example would be:

.test 5 10 5 n:sp

So far i got it to work all smoothly the way i want, but now what IF a user types in for example:

.test abc def ghi 10:5

I need the script to make sure that the first 3 inputs are NUMBERS ONLY, and the last part can ONLY be the LETTERS n, kb, sp, either single or combined with a : as a separator (such as n:kb:sp or just kb or even n:sp etc..).

If one of the first 3 inputs is NOT a number, i would like it to return an error, and if the last part (modes) is NOT one of the allowed letters, to have it return an error as well.

In addition to this, there are a total of 4 arguments. If the arguments are more than 4, return an error, and if the arguments are less than 4, to return an error as well. BUT, if the argument is just 1, as i have defined in the script below (-help or off), to not count this as an error.

Code:
proc test {nick host hand channel text} {
    set modes [lrange [split $text] 0 end]
    set help [lindex [split $text] 0]
    set h "-help"
    set o off
    if {$modes == ""} {
        putserv "NOTICE $nick :Missing arguements. Please type \002.test -help\002 for information on how to use this command."
        return 1
    }
    if {$help == $h} {
        putserv "NOTICE $nick :Set & Activate TEST"
        putserv "NOTICE $nick :This is the help description of the command \002test\002."
### I have subsituted the meanings with num1, num2, num3 to show you that the value MUST be only numerical digits, whereas <modes> must and only be either a sp, kb, n or a combination like sp:kb or n:kb, or even sp:kb:n ###
        putserv "NOTICE $nick :usage: .test <num1> <num2> <num3> <modes>"
        putserv "NOTICE $nick :example: .test 5 20 5 n:sp"
        putserv "NOTICE $nick : "
        putserv "NOTICE $nick Valid modes are sp for sapart, kb for kickban, n for notify"
        putserv "NOTICE $nick :To dectivate TEST type: .test off"
        return 1
    }
    if {$help == $o} {
        putserv "NOTICE $nick :TEST have been de-activated for channel $channel"
        return 1
    }
    putserv "NOTICE $nick :Channel TEST features for channel $channel have been set to \002[lindex [split $text] 0] [lindex [split $text] 1] [lindex [split $text] 2] [lindex [split $text] 3]\002"
    putserv "NOTICE $nick :In english this means, <num1> = \002[lindex [split $text] 0]\002, l<num2> = \002[lindex [split $text] 1]\002, <num3> = \002[lindex [split $text] 2]\002, and finally the <modes> = \002[lindex [split $text] 3]\002"
    return 1
}


The reason for all this is, that the final version, will execute various .chansets, and for security reasons the user's input MUST be limited to the above mentioned.

Any help would be be appreciated.

Cheers. 3
Back to top
View user's profile Send private message
dirty
Halfop


Joined: 08 Feb 2013
Posts: 40
Location: Romania

PostPosted: Thu Mar 14, 2013 5:49 am    Post subject: Reply with quote

try using [isnumber] and [regsub] for that
_________________
come to the dark side.. I have cookies!
WwW.BotZone.TK
Back to top
View user's profile Send private message Visit poster's website
Get_A_Fix
Master


Joined: 07 May 2005
Posts: 206
Location: New Zealand

PostPosted: Thu Mar 14, 2013 10:57 am    Post subject: Reply with quote

Before there was [isnumber] we had [isnum] Razz

Use this method, in the procs

Code:

proc test {nick host hand channel text} {
    set firstarg [lindex [split $text] 0]
    set secondarg [lindex [split $text] 1]
    set thirdarg [lindex [split $text] 2]
    if {![isnum $firstarg]} {putquick "NOTICE $nick :That is not a number. Please type \002.test -help\002 for information on how to use this command."; return}
    if {![isnum $secondarg]} {putquick "NOTICE $nick :That is not a number. Please type \002.test -help\002 for information on how to use this command."; return}
    if {![isnum $thirdarg]} {putquick "NOTICE $nick :That is not a number. Please type \002.test -help\002 for information on how to use this command."; return}
    set help [lindex [split $text] 0]
    set h "-help"
    set o off
    if {$modes == ""} {
        putserv "NOTICE $nick :Missing arguements. Please type \002.test -help\002 for information on how to use this command."
        return 1
    }


then add this to the last script loaded...

Code:

proc isnum {string} {
  if {[regexp {^-?\d+(\.\d+)?$} $string]} {
    return 1;
  }
  return 0;
}

_________________
We explore.. and you call us criminals. We seek after knowledge.. and you call us criminals. We exist without skin color, without nationality, without religious bias.. and you call us criminals.
Back to top
View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger
dirty
Halfop


Joined: 08 Feb 2013
Posts: 40
Location: Romania

PostPosted: Thu Mar 14, 2013 3:35 pm    Post subject: Reply with quote

why the hell should he use [isnum] and make a proc for that since [isnumber] is already in the eggdrop
_________________
come to the dark side.. I have cookies!
WwW.BotZone.TK
Back to top
View user's profile Send private message Visit poster's website
caesar
Mint Rubber


Joined: 14 Oct 2001
Posts: 3741
Location: Mint Factory

PostPosted: Fri Mar 15, 2013 2:30 am    Post subject: Reply with quote

Where's $modes variable declared?

why not use scan instead?

something like:
Code:

if {[scan $text {%d%d%d%s} fist second third last] != 4} {
# do whatever as the syntax is not valid
return
}
# do whatever as syntax is valid

or if you insist instead of:
Code:

    set firstarg [lindex [split $text] 0]
    set secondarg [lindex [split $text] 1]
    set thirdarg [lindex [split $text] 2]

a simple scan would do this:
Code:

if {[scan {%s%s%s} firstarg secondarg thirdarg] != 3} {
# do whatever as the syntax is not valid
return
}
# do whatever as syntax is valid

_________________
Once the game is over, the king and the pawn go back in the same box.
Back to top
View user's profile Send private message
LoKii
Voice


Joined: 21 Oct 2009
Posts: 34

PostPosted: Sat Mar 16, 2013 2:50 am    Post subject: Reply with quote

Thank you all for your imput, sorry for my delay in responding. I will sit down today and tackle this with what all of you have proposed here, and I will let you know how it turns out Smile
Back to top
View user's profile Send private message
LoKii
Voice


Joined: 21 Oct 2009
Posts: 34

PostPosted: Sun Mar 17, 2013 4:06 am    Post subject: Reply with quote

Well caesar, simply put I didn't even know of it's existence (the scan). Your solution has so far partially helped me a great deal. Whilst i also did like the solution prestented by Get_A_Fix, by using directly isnumber instead of isnum only for the fact that i could customize the response based on every argument separately, i still chose the scan method, just to keep the code a bit shorter, and also there seems to be a regex support using scan, which does bring me to my next point.

My next point was to limit the input possibilites to only certain characters & symbols, and using regex seems the right way to go. Now at first i thought of various approaches, as in letting the final argument be either settled by a separate if statement of its own using only regex in there, or if the scan's regex would also suffice. ( I guess this shows that I have no idea whatsoever about regex, and all ths stuff i read online just made me stay away from it, for as long as possible). But seeing now that I just simply NEED it whether i like it or not, i had to sit down and find a source that would explain it to me.

A friend of mine dropped of a book by O'reilly - Mastering Regular Expressions. I spent all day yesterday focusing just on that book, reading and I'm literally kicking myself in the a$$ that i did not go into regex earlier in my life. Its the MOST useful thing, and addictive as hell. So i will be solving my last issue once i understand how to perform the regex i need for my particular solution.

Below is just a small modification of the code. Changed the variable's names a bit for clarity sake, and added caesar's scan method. As you can see below, i need to implement the regext at the %s ($modes), so i hope that by tomorrow (after spending all day too to read on regex) that i will have a solution that suits my needs.

Code:
proc test {nick host hand channel text} {
    set syntax [lrange [split $text] 0 end]
    set 1 [lindex [split $text] 0]
    set 2 [lindex [split $text] 1]
    set 3 [lindex [split $text] 2]
    set modes [lindex [split $text] 3]
    set h "-help"
    set o off
    if {$syntax == ""} {
        putserv "NOTICE $nick :Missing arguements. Please type \002.test -help\002 for information on how to use this command."
        return 1
    }
    if {$1 == $h} {
        putserv "NOTICE $nick :Set & Activate TEST"
        putserv "NOTICE $nick :This is the help description of the command \002test\002."
        putserv "NOTICE $nick :usage: .test <num1> <num2> <num3> <modes>"
        putserv "NOTICE $nick :example: .test 5 20 5 n:sp"
        putserv "NOTICE $nick : "
        putserv "NOTICE $nick Valid modes are sp for sapart, kb for kickban, n for notify"
        putserv "NOTICE $nick :To dectivate TEST type: .test off"
        return 1
    }
    if {$1 == $o} {
        putserv "NOTICE $nick :TEST have been de-activated for channel $channel"
        return 1
    }
    if {[scan $syntax {%d%d%d%s} $1 $2 $3 $modes] != 4} {
      putserv "NOTICE $nick :Invalid arguements. Please type \002.test -help\002 for information on how to use this command."
      return 1
   }
    putserv "NOTICE $nick :Channel TEST features for channel $channel have been set to \002$1 $2 $3 $modes\002"
    putserv "NOTICE $nick :In english this means, <num1> = \002$1\002, <num2> = \002$2\002, <num3> = \002$3\002, and finally the <modes> = \002$modes\002"
    return 1
}


Many thanks to everyone here for their great help and support.

I will post the final code once it works.

In the mean time, maybe someone could give me an opinion on performance issues based on how I wrote that code in general? I don't like that i use so many lines for set. Maybe there is a more elegant way to go about this? (Would be nice to adapt more elegant approaches from now to avoid bad habits, rather than having to cut bad habits later on.

Cheers everyone Smile
Back to top
View user's profile Send private message
caesar
Mint Rubber


Joined: 14 Oct 2001
Posts: 3741
Location: Mint Factory

PostPosted: Sun Mar 17, 2013 7:50 am    Post subject: Reply with quote

Code:

proc test {nick host hand channel text} {
   set syntax [lrange [split $text] 0 end]
   scan $syntax {%s%s%s%s} 1 2 3 modes
   set h "-help"
   set o "off"
   if {[string match -nocase $1 $h]} {
      puthelp "NOTICE $nick :Set & Activate TEST"
      puthelp "NOTICE $nick :This is the help description of the command \002test\002."
        puthelp "NOTICE $nick :usage: .test <num1> <num2> <num3> <modes>"
        puthelp "NOTICE $nick :example: .test 5 20 5 n:sp"
        puthelp "NOTICE $nick Valid modes are sp for sapart, kb for kickban, n for notify"
        puthelp "NOTICE $nick :To dectivate TEST type: .test off"
        return
   }
   if {[string match -nocase $1 $o]} {
      puthelp "NOTICE $nick :TEST have been de-activated for channel $channel"
      return
   }
   if {![info exists $modes]} {
      puthelp "NOTICE $nick :Missing arguements. Please type \002.test -help\002 for information on how to use this command."
   } else {
      puthelp "NOTICE $nick :Channel TEST features for channel $channel have been set to \002$1 $2 $3 $modes\002"
      puthelp "NOTICE $nick :In english this means, <num1> = \002$1\002, <num2> = \002$2\002, <num3> = \002$3\002, and finally the <modes> = \002$modes\002"
   }
}

Haven't tested. Razz
_________________
Once the game is over, the king and the pawn go back in the same box.
Back to top
View user's profile Send private message
Get_A_Fix
Master


Joined: 07 May 2005
Posts: 206
Location: New Zealand

PostPosted: Sun Mar 17, 2013 8:17 pm    Post subject: Reply with quote

dirty wrote:
why the hell should he use [isnum] and make a proc for that since [isnumber] is already in the eggdrop


Did you notice where I said "Before there was [isnumber] ..." ???

It was merely an example of how it 'was' achieved in my instance.
_________________
We explore.. and you call us criminals. We seek after knowledge.. and you call us criminals. We exist without skin color, without nationality, without religious bias.. and you call us criminals.
Back to top
View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger
LoKii
Voice


Joined: 21 Oct 2009
Posts: 34

PostPosted: Mon Mar 18, 2013 2:15 am    Post subject: Reply with quote

Hello everyone again,

Hey, no need for arguing about why this method, and not that. All point of views are of interest, since non of your suggestions here have been known to me in the first place. Its nice to see all the possibilities even if some are obsolete or over complicated.

Ok, back on track. I have read up on various regex solutions. In some extra test code i have tried various approaches using regexp, and others. However, i would like to stick with the scan solution.

When it comes to the scan solution, non of the regex seems to be applied or work for me (based on what i have read about regex).

To simplify the process of getting regex to work inside a scan, lets dumb down the 4th argument to just a single character k. Later on I can continue to expand the regex rules, once i get this basic one running.

What i have tried so far, but with no luck whatsoever is:

Code:
if {[scan $syntax {%d%d%d%[k]} $1 $2 $3 $modes] != 4} {

if {[scan $syntax {%d%d%d%[[k]+ $]} $1 $2 $3 $modes] != 4} {

if {[scan $syntax {%d%d%d%[(k)+ $]} $1 $2 $3 $modes] != 4} {

if {[scan $syntax {%d%d%d%[^[k]+ $]} $1 $2 $3 $modes] != 4} {

if {[scan $syntax {%d%d%d%\[k\]+ $} $1 $2 $3 $modes] != 4} {

if {[scan $syntax {%d%d%d%[^[k+] ]} $1 $2 $3 $modes] != 4} {


and many other combinations that I have now forgotten whilst writing this post here.

Some of the methods I have tried would either return various errors, others would just simply ignore the 4th argument of code totally.

From my understanding, at least the 1st line should work? %[k].

From my examples here, what i wish to achieve is to ONLY accept the k as a valid entry for the 4th argument of the code, and nothing else. I solved more complicated regex quizzes whilst reading about them, but i can not get any regex working with this tcl scan.

What am i missing? I would like to keep the idea of using scan rather than using regexp (which seems to have a performance difference in speed, and most people recommend scan for this type of situation).


caesar, thank you for your code above, I have not got about to trying it yet, as i want to solve the regex issue first, but once that is sorted, i will look into the modifications you have made for the performance issues.

Cheers everyone Smile
Back to top
View user's profile Send private message
SpiKe^^
Owner


Joined: 12 May 2006
Posts: 792
Location: Tennessee, USA

PostPosted: Mon Mar 18, 2013 11:21 am    Post subject: Reply with quote

First off,
$1 $2 $3 $modes
should be...
1 2 3 modes
without all the $'s
_________________
SpiKe^^

Get BogusTrivia 2.06.4.7 at www.mytclscripts.com
or visit the New Tcl Acrhive at www.tclarchive.org
.
Back to top
View user's profile Send private message Visit poster's website
LoKii
Voice


Joined: 21 Oct 2009
Posts: 34

PostPosted: Tue Mar 19, 2013 4:55 am    Post subject: Reply with quote

SpiKe^^ wrote:
First off,
$1 $2 $3 $modes
should be...
1 2 3 modes
without all the $'s


Thank you for pointing that out. Thanks to that, the error messages changed in to something that made more sense to me, and i finally figured out how to go about the regex issues i had.

So, now i managed to get the regex to actually 'do' something.

To sort out the issue i have now, let us let the regex filter out the following characters: a b cd
My regex so far looks like:

Code:
"^\[ab(cd)\]?$\"


My issue is, that the a or the b are identified correctly. However, the cd is still messy due to the ? (limiting it to a single char). if i were to use a + instead of a ?, then the problem is that i can use cd / ccdd / cddd / cccd etc....

In my attempt to seperate the a and the b from the cd, i tried the following (just to give me some play-space for now):

Code:
"^\[ab\]?$\|^\[cd\]+$"


In this version, i can limit the a and b to a single character, however the cd can still be fooled by ccdd and such variants.

In the traditional regex (not tcl), a way to fix this would be:

Code:
"^\[ab(cd)\]?$\"


meaning that I would group the cd using (), but this does not seem to work in TCL for me because the ? still limits my input to 1 character only, and the + allows a surplus of characters.

Any tips on what I am looking for to fix this?

Cheers.
Back to top
View user's profile Send private message
LoKii
Voice


Joined: 21 Oct 2009
Posts: 34

PostPosted: Tue Mar 19, 2013 8:39 am    Post subject: Reply with quote

Small update. Managed to get rid of the problem when repeating some of the chars, such as ccdd ccd cdd and so on.
Code:

"^\[ab\]?$\|^\[cd\]{2}$"


However now, i still have 1 last headache left. I am still able to use cc or dd. Any suggestions?


//edit

Ok, i found a full working solution.

Code:
"^\[ab\]?$\|^(c)\[\1d\]$"


This version works the way i need it to.

Now then, is there maybe any recommended cosmetic change to this? Maybe something that makes a difference in performance, or security?

Below is the entire code that i have so far (with a few changes based on caesar's rewrite).

Code:
proc test {nick host hand channel text} {
    set syntax [lrange [split $text] 0 end]
    foreach {1 2 3 4} [split $syntax] {break}
    set h "-help"
    set o off
    set m "^\[ab\]?$\|^(c)\[\1d\]$"
    if {$syntax == ""} {
        putserv "NOTICE $nick :Missing arguments. Please type \002.test -help\002 for information on how to use this command."
        return 1
    }
    if {[string match -nocase $1 $h]} {
        putserv "NOTICE $nick :Set & Activate TEST"
        putserv "NOTICE $nick :This is the help description of the command \002test\002."
        putserv "NOTICE $nick :usage: .test <num1> <num2> <num3> <modes>"
        putserv "NOTICE $nick :example: .test 5 20 5 <a | b | cd>"
        putserv "NOTICE $nick : "
        putserv "NOTICE $nick :To de-activate TEST type: .test off"
        return 1
    }
    if {[string match -nocase $1 $o]} {
        putserv "NOTICE $nick :TEST have been de-activated for channel $channel"
        return 1
    }
    if {([scan $syntax {%d%d%d%s} a b c prefs] != 4) || (![regexp $m $prefs])} {
      putserv "NOTICE $nick :Invalid or missing arguments. Please type \002.test -help\002 for information on how to use this command."
      return 1
   }
   putserv "NOTICE $nick :Channel TEST features for channel $channel have been set to \002$a $b $c $prefs\002"
   putserv "NOTICE $nick :In English this means, <num1> = \002$a\002, <num2> = \002$b\002, <num3> = \002$c\002, and finally the <modes> = \002$prefs\002"
   return 1
}


Please do criticize and make recommendations to what could be better.

Cheers everyone and thank you all for your help.
Back to top
View user's profile Send private message
nml375
Revered One


Joined: 04 Aug 2006
Posts: 2857

PostPosted: Tue Mar 19, 2013 1:39 pm    Post subject: Reply with quote

One hint when working with regular expressions, if you use curly brackets instead of quotes, you don't have to bother with escaping the string from the tcl parser..

As for your pattern, I find it somewhat overworked. If you merely would like to match either a, b, or cd, this would suffice:
Code:
set m {^(a|b|cd)$}

_________________
NML_375, idling at #eggdrop@IrcNET
Back to top
View user's profile Send private message
LoKii
Voice


Joined: 21 Oct 2009
Posts: 34

PostPosted: Tue Mar 19, 2013 2:03 pm    Post subject: Reply with quote

nml375 wrote:
One hint when working with regular expressions, if you use curly brackets instead of quotes, you don't have to bother with escaping the string from the tcl parser..

As for your pattern, I find it somewhat overworked. If you merely would like to match either a, b, or cd, this would suffice:
Code:
set m {^(a|b|cd)$}


I was wandering, why I am the only one on the forums here who actually had to escape almost everything in the string to get it to work, whilst looking at other people's syntax.

I tried your code, but it doesn't work. As for the error, I'm not sure why not (since the error returned is my custom error). I simply replaced your set m with my set m.

How would i go about getting an error message as to why your code wont work?

I sure as hell would not mind to get a shorter version of it working.

I have applied this test code (the one that I have made) to also work for AllProtection script, as to make some aspects of it public.

The version I used for the AllProtection was:

Code:
set pmeth "^\[wk\]?$\|^(k)\[\1b\]$\|^\[w\]:?\[k\]?$\|^\[w\]:?(k)\[\1b\]$\|^\[k\]:?(k)\[\1b\]$\|^\[w\]:?\[k\]:?(k)\[\1b\]$"


And yes, I would LOVE to find a more elegant/shorter way of getting the same results.

The goal of this whole regex issue is to make sure that any input which would not be recognized by the AllProtection script, should be invalid. This is just to make sure that if someone does not understand the syntax that Allprotection wants, that he could not enter something invalid, or even maybe something potentially dangerous, since at the end of the day, it does end up doing a .chanset.

I just dont get, why whenever i try to avoid escaping characters, nothing works for me Sad

But hey, this is day 3 for me on learning regex. I definately want to get much more involved with regex in general, since it is highly addictive.

In addition to this, i have also read many opinions here on the forums to maybe try to use string map instead of regexp for performance. And initially i wanted to avoid using regexp in the first place, thinking i could just add the regex to the scan. Didnt work out for me like i had hoped, so i used the regexp solution.

I definitely will be checking for the string map too for other solutions that i am still in the process of working on.

Cheers.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    egghelp.org community Forum Index -> Script Requests All times are GMT - 4 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Forum hosting provided by Reverse.net

Powered by phpBB © 2001, 2005 phpBB Group
subGreen style by ktauber