Programming TCL scripts Артикъл за програмиране на TCL скриптове за Eggdrop... доста изчерпателен и пълен.

Ако ви се е повредил Windows, не знаете какво да правите с Linux или не знаете как се правят аквариуми - това е мястото за вас
Аватар
LuD
The Sinner's Priest ;-]
The Sinner's Priest ;-]
Мнения: 205
Регистриран на: 10 Окт 2012 15:44
Местоположение: Sofia
Обратна връзка:

Programming TCL scripts Артикъл за програмиране на TCL скриптове за Eggdrop... доста изчерпателен и пълен.

Непрочетено мнение от LuD »

Написан от: Юлиян Петров (rhodie) и Станислав Захариев (sofit)
PS: Извиняваме се за правописните грешки :))


В този турориал ще се опитаме да ви разясним как да правите скриптове за eggdrop ботове.Ще бъдат използвани примери за да се обяснят командите и ще се опитаме да направим всичко възможно най просто за обяснение и разбиране. След това би трябвало да знаете по принцип как да пишете различни видове скриптове. Ще разберете описаното в tcl-commands.doc и man TCL страниците (поне се надяваме). Предлагаме ви да погледнете в tcl-commands.doc след като прочетете това, защото ако разберете всичко за което се говори тук и знаете повечето команди и binds в tcl-commands.doc ще бъдете експерт в писането на TCL скриптове за Eggdrops.

TCL езикът не идва специално от Eggdrop. Това е език използван от Eggdrop. За да ви помогнем да разберете нещата по-добре
ще започнем с какво точно е TCL и какво прави.

TCL е с отворен код. Това озбачава че програмата ви се пуска като изпраща сорс кода (самият скрипт) към TCL програма
която го обработва без да го компилира както другите езици като С но не и като Perl ;)). Това означава че хората
могат винаги да погледнат в програмата ви и да видят как е написана, затова ще имате по малко проблеми с несъвместимоста
на различните операциони системи защото TCL езикът е винаги един и същ навсякаде.

Командите в TCL скриптът могат да се разделят на две части. Първата е когато стартирате скриптът а другата когато ги
извикате. Командите които се стартират когато стартирате скриптът са извън процедурите (покъсно ще обясним как можете да
дефинирате процедури).

Както всички програмни езици трябва да слагате конкретни сепаратори м/у специалните символи за да знае езикът какво да
прави с тях. TCL използва следните символи за да дефинира събитията:

<> - по-голям от колкото и по-малко
Тези два знака не се използват в TCL сами, но се използват в документацията за да индикират какви параметри са нужни ако
искате да изпълните команда.

"" - кавички
Кавичките се използват за да маркират текст. Всичко м/у "" се счита за текст, освен ако не е заобградено със скоби или е
маркирано като променлива (за тях ще научите по късно).

[ ] - скоби
Скобите се използват за да се изпълни команда. Първата дума в скобите е командата която искате да изпълните а следващите
са параметрите на тази команда. Също така се използват в документацията за да индикират кои параметри са оптимални и кои
не се изискват за да се използва дадена команда.

{ } - скоби
Braces се използват за да покажат кога нещо започва и спира. Това може да бъде част от скрипт или команда.

( ) - скоби
Скобите се използват за да дефинират различни неща. Използват се също да дефинират че дадената променлива е масив и че отдел
ните части на [if] командата си пренадежат пример за това ще бъде даден по късно.

$ - променлива
Това дефинира, че думата която следва след $ (без празни места в нея) е променлива.
Казано накратко променливата е мястото където вие запазвате информацията за по-късно използване. Това ще бъде
дискутирано по-късно по-обширно.

; - точка и запетая
Когато TCL види точка и запетая, процедира с всичко, което е след него сякаш е на нов ред. По такъв начин можете да
сложите няколко команди на един ред да направите скриптаси по-кратък и все още работещ.
Ако не използвате точка и запетая и сложите втора линия след първата, TCL ще разбере това като параметър към първата
(която е пред нея) и в повечето случаи ще даде грешка, защото командата би трябвало да няма такъв параметър,
или прави скрипта ви грешен.

# - диез
Когато TCL види диез в началото на линията, той смята всичко след нея като коментар и ще го игнорира и ще прескочи на
следващата линия.
Много програмни езици казват от къде започва коментара и къде свършва , както в HTML дефинирате започването на
коментара с <!--, а където свършва коментара пишете --> или в C където коментара започва с /* и завършва с */.
Това не се отнася за TCL. Когато сте сложили диез в началото на линията, всичко след нея (на тази линия)
ще бъде игнорирано. Забележете,че не можете да сложите диез по средата на линията и да сложите коментара след нея, защото
това ще даде грешка, защото TCL няма да види коментара като коментар в този случай. Вместо това можете да сложите точка
и запетая отпред на диеза така че TCL да интерпретира нещата така сякаш всичко това е било на нов ред и така линията ще
започне с диез и всичко след нея ще се смята за коментар.
Малко е сложничко, но така е начина по който работи и не мисля, че някога ще се смени, ще свикнете ;). Веднъж щом разберете
как работи не е толкова сложно.

\ - наклонена черта
Наклонената черта се използва, за да накара TCL да види следващия символ като текст. По начало когато използвате скоба
във вашият скрипт TCL трябва да я види като начало или край на команда, но когато използвате наклонена черта пред нея
TCL ще я види като обикновен текст и ще преработи скобата вместо да се опитва да изпълни командата. Има няколко изключения
към това. Има няколко кода, които започва с наклонена черта последва с номер или буква, за да създадат специални символи.
В тези случаи наклонената черта означава, че има специален код и да не се гледа следващият символ като текст.
Например: \0 (това е числото 0, не буквата o) нормално TCL би трябвало да види 0 като текст (TCL вижда по принцип 0,но
наклонената черта го изпълнява и това не е точно пример за това как работи), но \037 не означава 037 като текст, а че
следващият текст трябва да бъде подчертан.
Това може да изглежда малко объркващо, както и да е един път разбрано как работи не е толкова трудно, както всичко в
TCL.

Понеже TCL не е нещо от Eggdrop, има два вида команди. Команди от самият TCL, които могат да работят и със скриптове
извън Eggdrop, и команди, които са добавени от Eggdrop.

Всички команди, които Eggdrop добавя към TCL са описани в tcl-commands.doc, който може да бъде намерен в doc/ директорията
на Eggdrop.

Можете да получите информация за командите в TCL от man страниците. Можете да ги видите като напишете
[man n <command>] на *nix компютър, който има тези страници инсталирани или да достигнете до тях чрез HTML
версията им на http://dev.scriptics.com/man/tcl8.0/TclCmd/contents.htm.

Сега ще обясним двете основни команди в TCL [bind] и [proc].
Тези две команди ви позволяват да накарете бота да изпълни действия, при конкретно събитие.

С [bind] командата можете да накарате ботът да отвръща на команди, съобщения или ctcp. Синтаксисът на [bind] командата е
[bind <type> <flags> <command> <procedure>]. Ще обясним това стъпка по стъпка.

<type> е на какво действие да реагира бота.
Например, [ctcp] ще отговаря на ctcp, а [msg] на съобщения.
Можете да намерите всичките възможни видове в eggdrop/doc/tcl-commands.doc.

С <flags> ще дефинирате какви флагове трябва да има потребителя във вашият Eggdrop във вид <глобален флаг|локален флаг>.
Ето няколко примера за да обясним по-бързо и просто:
# Отговаря на всички (включително и на тези, които не са аднати в бота).
bind <type> - <command> <procedure>

# Отговаря на всички (включително и на тези, които не са аднати в бота).
bind <type> * <command> <procedure>

# Отговаря на глобалните owners
bind <type> n <command> <procedure>

# Отговаря на глобалните оператори
bind <type> o <command> <procedure>

# Отговаря на локалните masters (НЕ на глобалните)
bind <type> -|m <command> <procedure>

# Отговаря на глоабални masters и на локални
bind <type> m|m <command> <procedure>

# Отговаря на глобални оператори и на локални owners
bind <type> o|n <command> <procedure>

<command> е за какъв параметър да се следи. Ако искате да следи за вид [msg],
параметърът трябва да е първата дума от съобщението или ако искате да използвате вид [dcc]
трябва да е нова команда, която искате да създадете за partyline.
Например [bind dcc <flags> test <procedure>] ще създаде partyline команда [test] или
[bind msg <flags> hello <procedure>] ще накара бота да отговаря когато получи съобщение започващо с "hello".

<procedure> е процедурата, която бота тярбва да стартира когато засече видът и командата, за която трябва да отговаря.

Процедурите не са нищо повече от команди, които можете да извикате навсякъде в TCL скрипта. Можете да извикате процедура
като напишете някъде в скрипта си [<procedure> [parameters]] (например процедура, някъде в скобите или просто в главния ви
скрипт).
Тези процедури изпълняват команди, които например могат да върнат стойност, след като проверят няколко фактора или могат да
изпратят нещо към IRC сървъра. Можете да следите за върнати RAW numerics от сървърът като на <type> сложите RAW, а за <command> numeric стойност-а. Обикновно се слага края на numeric-а и същинската част която връща. Всичките numeric стойности които сървърът ви връща можете да видите на
http://irchelp.unibg.org/irchelp/IRC/Do ... eaders.htm можете да ползвате и следния TCL скрипт за да видите за какво по точно става

С [proc] командата можете да създавате процедури. Синтаксиса е [proc <name> { <parameters> } { <body> }].

<name> е името на процедурата, която създавате. Това може да бъде всичко, което поискате и трябва да използвате това име
когато искате да я извикате.

<parameters> представляват стойностите, които процедурата трябва да приеме. Трябва да зададете стойности за всеки параметър,
който ще бъде изпратен към процедурата. Всички стойности, които дадете трябва да бъдат отделени с празно място.
Например, ако имате линията [proc test { nick channel } { <body> }]
и някъде другаде във вашият скрипт [test MyNick #test], процедурата ще сложи "MyNick" в стойността
"$nick" и "#test" в "$channel".

Процедурата винаги иска да знае точната големина на параметрите, които сте задали. Ако дадете на процедурата 4 стойности, а
тя изисква 5, Eggdrop ще даде грешка подобна на 'proc called with too many arguments', а ако я извикате с 3
"no argument given for ...".

Има изключение на това правило. Ако именувате последната стойност на <parameters> с името "args", тогава можете да я
извикате с повече параметри, отколкото са дефинирани.
В този случай всички параметри, които сте задали на процедурата, от "args" нататъка ще се съдържат в $args.
Те се поставят в $args сякаш е използвана командата
  • за тази цел. Ще научите повече за
    • командата, но вече
      трябва да знаете за разликата между "args" и всяко друго име.
      Например, ако извикате процедурата [proc test { nick channel args } { <body> }] с
      [test $nick $channel $handle $host], ще сложи $nick в $nick, $channel в $channel, а $handle and $host в $args,
      но ние ви разубеждавам да използвате командата "args" като параметър, поне докато научите какво е
      прави командата
      • .

        <body> са командите, които искате процедурата да изпълнява. <body> не трябва да бъде на една линия, затова
        процедурата започва с една отворена скоба. Можете да сложите отделна команда на нов ред и тя ще бъде част от процедурата
        докато не затворите <body> със скоба.

        Освен ако не извикате процедурите ръчно, в повечето ще искате да използвате [bind].
        [bind] командата стартира процедурата, когато конкретното действие е засечено. Освен за
        bind, tcl-commands.doc също така ви дава информация какви параметри са нужни на процедурата и информация за параметрите
        които садържа.

        Нека да разгледаме [bind msg] обяснението от tcl-commands.doc:
        (1) MSG
        bind msg <flags> <command> <proc>
        procname <nick> <user@host> <handle> <arg>

        Всичко след [procname] са параметри, които ще бъдат изпратени към процедурата. Повечето процедури за
        [bind msg] ще изглеждат подобно на [proc msg_test { nick host hand arg } { <body> }].

        Накрая разбира се затоверете body процедурата със скоба, можете да използвате командата [return], за да накарете
        процедурата да свърши където искате от body. Сега процедурата ще завърщи зависейки от това как използвате return командата.
        Синтаксисът на [return] командата е [return <message>.]

        <message> е това което процедурата трябва да изпише. По принцип завършвате процедурата с 0 или 1 като <message>.
        В повечето случаи 0 като <message> ще последва като бърз отговор, при което бота ще продължи нормално сякаш bind-а не
        съществува, това означава, че няма да логне нищо и няма да препокрие вградени функции като flood защиатата например.
        Когато връщате 1 бота обикновено логва командата която е била извършена като например [bind dcc] или изобщо не реагира на
        действието (когато използвате [bind flood], връщайки 1 бота няма да реагира на флуда но ще позволи на TCL скрипта да
        противодейства). Можете да намерите повече в tcl-commands.doc за това как повечето bind реагират на return стойността.

        Освен 0 или 1 процедурата return може да връща и текст ако го искате. Което грубо казано ще направи процедурата да действа
        като интерактивна променлива. Все още трябва да я извиквате с [proc [parameters]], но ще връжа информацията както променлива
        та би направила това. Например, [proc test { nick } { return "Hello $nick." }] ще бъде същото като [set test "Hello $nick."]
        само че ще го извикате по по-различен начин и можете да проверите някой неща с процедурата и евентуално да изпише нещо
        различно от входа, но все още да държите изходните като променлива.

        Вече се сблъскахте с термина променлива няколко пъти, но сега ще обясним какво точно е това.

        Променливите се използват в почти всички TCL скриптове. За сега не сме виждали TCL скрипт който да не ги използва.
        Променливата е нещо в което можете да държите информация. Тази информация може да бъде всякаква и е динамична. Може да бъде
        различна всеки път когато викате процедурата или скрипта.

        В много програмни езици има различни типове променливи. Трябва да обявите всяка променлива и също дали е номер или ще
        съдържа букви. Това не се отнася за TCL. В TCL всяка променлива е така нареченият string, което означава че няма значение
        дали съдържа числа или букви, може да бъде едно от тях или и двете.

        Това ограничава малко нещата които можете да правите с тях, но прави езикът доста по лесен. Сега вече ще разглеждаме
        променливите като стринг.

        Стринговете могат да бъдат дефинирани и изтрити с [set] и [unset] командите.
        Синтаксисът на set командата е [set <string> <value>] а на unset командата [unset <string>].
        Освен [set] и [unset] съществува също и [append].
        Тази команда работи по същият начин като [set] командата, но празликата е че тази команда добавя нещо към стринга без да го
        променя.[append] командата добавя нещо директно към краят на стринга което е също като [set <string> "$<string><value>"].


        <string> е името на стринга който искате да промените.
        Името трябва да съдържа букви, тирета (-) и/или само номера. Ако сложите някой друг символ в него може да доведе до грешки
        защото скрипта ги интерпретира грешно.

        <value> съдържа това което искате да има в стринга и това което искате да бъде добавено към стринга ако използвате [append].
        Това може да е число, някакъв текст, върнатата стойност от някаква команда или всичко което ви се струва правилно за тази
        цел. Това което можете да сложите в стринга не се ограничава с нищо, но някой символи трябва да бъдат избегнати чрез наклоне
        на черта за да сме сигурни TCL няма да ги интерпретира грешно. Забележете също че ако искате да сложите част от текст
        в стринг можете да го обградите в кавички.

        Освен да дефинирате стринг, можете и да го изтриете. Това просто ще направи стринга несъществуващ отново както е бил преди
        да го създадете.

        ВНИМАНИЕ: TCL ще върне грешка когато се опитате да използвате стринг който не съществува (макер че стринга може да
        съществива когато няма нищо в него, ([set test ""])).

        Освен нормалните стрингове има и масиви.
        Масива е група от стрингове свързани заедно "под един покрив". Можете да използвате тези масиви по същият начин по който
        използвате нормалните стрингове. Най-голямото преимущество на масивите над нормалните стрингове е това че те са под един
        покрив и могат да бъдат достигнати всичките наведнъж чрез някои команди, правейки го по лесно за вас, не е нужно да
        проверявате всички стрингове един по един понеже целият масив е вече зареден.

        Синтаксисът на масива е [$array(string)], кадето [array] е името на масива и [string] е името на стринга в масива.
        Веднъж създали масив не можете да създадете стринг със същото име. Например ако имате $test(<string>), няма да можете да
        имате и $test.

        Ето няколко примера:
        # Слагате думата "that" в стринга [what] от масива [test]
        set test(what) "that"

        # Слагате думата "now" в стринга [when] от масива [test]
        set test(when) "now"

        # Следното ще изкара грешка понеже вече има масив с името test!
        set test "testing"

        # Слага думата "what" в стринга [test_what]
        set test_what "what"

        # Слага думата "now" в стринга [test_when]
        set test_when "now"

        Веднъж щом сте създали масив може би ще искате да вземете списък с всичките стрингове които той съдържа, например вземане
        на списък от масива $test() от предишният пример.

        Командата използвана за тази цел е [array names].
        Синтаксисът на командата [arrayn names] е [array names <array>].
        В този случай <array> е името на масива от който искте да вземете имената, например "test" както е в нашият пример.

        Сега ако сложим [array names test] в предният пример, ще върне "what" и "when".

        Предполага се че това няма да ви потрябва но по късно може да ви се стори много полезно.

        Има два типа стрингове. Локални и глобални. Локалният стринг същестува само в процедурата в която е дифиниран, а глобалният
        стринг съществува през цялото време през което скриптът ви е пуснат и през което ботът е пуснат.
        Всички стрингове създадени извън процедура автоматично стават глобални като се използва командата [global]. Глобалните и
        локалните работят по сходен начин, единствената разлика кога и каде те съществуват.

        Синтаксисът на командата global е [global <strings>].
        Всеки стринг трябва да бъде разделен от празни места и ако искате да имате глобален масив, трябва просто да дадете името на
        масива, но не и името ма стринга от масива.

        Също и защото тази команда вече знае какво давате за вход към стринга, вие не трябва да слагате $ пред името на стринга ви.
        $ се използва за да се идентифицира нещо като стринг и да се препокрие часта със съдържанието на стринга.
        Когато сложите $ ще се препокрия цялото име на стринга заедно с $-то със съдържанието на стринга. Например ако $test съдържа
        "hello" и вие напишете [global $test], TCL ще го сметне за [global hello] а това не е това което искате в този случай, нали?

        Ще вземем [set] командата за пример кадето имаме масива [test] с стрингове "(when)" и "(what)" , също не е нужно да използвате
        команда като [global test(when) test(what)], но можете да използвате [global test] което ще даде достъп на глобалните стрингове
        "(what)" и "(when)" до масива [test]. Глобалната команда превръща целият масив, не само индивидуалния стринг.

        За финал: командата [global] се обикновено се слага на първъят ред на процедурата. Това не е задължително, но е нещо като
        неписано правило. Също е и по лесно да се разгледа вашият скрипт ако [global] е на първият ред вместо да е някаде скрит в
        процедурата.


        С командата [incr] лесно добавяте/изваждате числа от стрингове.
        Синтаксисът на [incr] командата е [incr <string> [+/-][number]].
        Ето няколко бързи и лесни примера които обясняват командата:

        Here are a few simple examples to explain the command fast and easy:

        # Добавя 1 към стринга [test].
        incr test

        # Добавя 2 към стринга [test].
        incr test 2

        # Добавя 3 към стринга [test] (знакът + не е задължителен).
        incr test +3

        # Изважда 4 от стринга [test] (знакът - е логически, задължителен за изваждането)
        incr test -4

        С командата [incr] можете само да +/-. Делението, умножението и неща като тях трябва да бъдат направени с командата
        [expr], но това ще оставим за по късно. Забележете че, стрингът с който работите трябва да бъде число или [incr] командата
        ще върне грешка.

        Сега да обясним как да изписвате информация.
        Има много команди с които можете да изпишете някаква информация, някои от тях се използват да се изпраща информацията към
        различни места, а някои да се изпраща по по различен начин.


        Има 4 команди с които можете да накарате Eggdrop да логне нещо.
        Тези команди са [putlog], [putcmdlog], [putxferlog] и [putloglev].
        Разликата м/у тези команди е че всяка команда изпраща лог съпбщението с различен лог левел (различните лог левели са описани
        в конфигурационият файл на бота). Ето и списък с лог левелите според eggdrop.complete.conf:

        # Събитията се логват според различни категории, по такъв начин да зададете точно какво събитие искате да бъде пратено
        # към различните лог файлове.
        #
        # Различните глагове за логване са:
        # m private msgs/ctcps към бота
        # k kicks, bans, mode changes в канала
        # j joins, parts, netsplits в канала
        # p public msg в канала
        # s server connects/disconnects/notices
        # b информация за свързването на бота и поделянето на потребителския файл
        # c команди които се използват от хората през msg или dcc
        # x файл трансфер и file-area команди
        # r (ако use-console-r е включена) ВСИЧКО изпратено до бота от сървърът
        # o други: разни информации, грешки -- ВАЖНИ НЕЩА
        # w wallops: съобщенията м/у IRCops (обедете се че бота има +w в init-server, и ботът да е оператор)
        #
        # Има и други, но сигурно няма да искате да ги логвате, по добре да бъде неетично ;) Има също и 8 левела дефинирани за потребителите
        # (1-8) които се използват от TCL скриптовете.

        [putlog] изпраща лог съпбщението с левел о, [putcmdlog] изпраща съобщенията с левел c, [putxferlog] изпраща съобщенията с
        левел х, и [putloglev] изпраща съобщенията с левел който зададете.

        Синтаксисът на командите [putlog], [putcmdlog] и [putxferlog] е [putlog "<text>"].
        Синтаксисът на командата [putloglev] е [putloglev <level(s)> <channel> "<text>"].

        <level(s)> е с какъв левел искате да пратите лог съобщението. Можете да изплзвате * за да пратите лог съобщението за
        всички левели.

        <channel> е за кой канал да се изпраща лог съобщение. Използвайте * за да се изпрати към главният лог.

        <text> е съобщението което искате да бъде логнато.

        Конзолните модове по подразбиране правят мастарите и овнърите да виждат всички съобщения с левел о в partyline.
        Защото [putlog] се използва главно за логване на команда и можете да бъдете сигурни че това което пратите ще се покаже на
        овнърите и мастърите в partyline-а. Което е добре понеже по този начин можете да направите скрипта ви да праща съобщения
        от събития към partyline-а за вашите мастъри и овнъри.
        Можете да го използвате и за debugging (намирайки каде нещо дава грешка). Слагайки [putlog] командата през няколко реда
        да изпраща съобщения към partyline-а много лесно можете да разберете къде скрипта ви греши, когато прави нещо което вие не
        искате. Без тези съобщения може да ви отнеме доста дълго време да откриете каде е грешката.

        Можете да изпратите съобщение на потребител от partyline-а с командата [putdcc].
        Стандартният синтаксис е [putdcc <idx> "<text>"].


        <idx> сочи към сокета към който съобщението ще бъде пратено. Всяко идващо и излизащо съобщение от вашият бот си има така
        наречен сокет номер. Такава връзка може да бъде връзката към IRC сървърът, към свързан бот или към потребител който е в
        partyline-а. Можете да видете сокет номерата на вашият бот които в момента се използват като използвате командата [dccstat]
        в partyline. Някой binds, като [bind dcc], изпращат сокет номера на потребителя който е изпълнил командата към процедурата
        след което вие можете да използвате сокет номера за да изпратите съобщение директно към него с командата [putdcc].

        <text> е съобщението. Например, [putdcc $idx "Hello"] ще изпрати "Hello" към сокет номера който се съдържа в $idx.

        Има 3 команди с които можете да изпращате команди към IRC сървъра.
        Тези команди са [putserv], [puthelp] и [putquick].
        Всички тези команди правят абсолютно едно и също нещо но се различават по привилегията която ползват.
        [putquick] командата има най-голяма привилегия и съобщението се изпраща веднага към сървърът.
        [putserv] командата използва нормални привилегии и се използва за изпращането на команда за която не трябва да се бърза.
        [puthelp] командата е с най-малки привилегии, използва се за пращане на съобщения и нотиси към други хора, защото това
        обикновено има много ниски привилегии.

        Синтаксисът на командите [putquick], [putserv] и [puthelp] е [putserv <text> [options]].


        <text> е командата и параметрите които искате да пратите към IRC сървърът.
        Ако искате да пратие съобщение към някой потребител или канал синтаксисът трябва да бъде
        ["PRIVMSG <nickname/channel> :<message>"] или ако искате да изпратите нотис
        ["NOTICE <nickname/channel> :<message>"], кадето nickname/channel е псевдонима или канала към който искате да изпратите
        съпбщението а <message> е съобщението което искате да пратите. Например [puthelp "PRIVMSG foo :Hi there."] ще изпрати съоб
        щение "Hi there." към псевдонима "foo".

        [options] са параметрите на командата. В момента има само един параметър и това е -next.
        Това ще придвижи вашата команда по напред и ще ви даде по големи привилегии и така ще я изшратите по бързо.
        Повече информация за IRC командите можете да намерите на http://irchelp.unibg.org/irchelp/IRC/Do ... fc1459.txt

        Има две команди с които можете да пратите команди към другите ботове.
        Те са [putbot] и [putallbots]. Както вече сте разбрали [putbot] ще изпрати командата само до определен бот, а [putallbots]
        ще изпрати команда до всички свързани ботове.
        Синтаксисът на командата [putbot] е [putbot <botnet-nick> <command>] а на командата [putallbots] - [putallbots <command>].

        <botnet-nick> е псевдонимът използван в BotNET-а (обикновено същият като нормалният) от бота към който искте да пратите
        съобщението.

        <command> е командата която ще бъде изпратена и параметрите към нея.
        Първата дума е обикновено командата която искате да пратите и на която [bind bot] ще реагира а останалото е допълнителна
        информация или параметри които искате да изпратите към нея които ще бъдат добавени като последен параметър към процедурата
        Забележете че и тук както при set командата, трябва да затворите <command> с кавички.

        Има два начина да промените модовете в канал.
        Това се прави ръчно с командата [putserv] или с предназначената за тази цел команда [pushmode] която е и по бърза.
        [pushmode] командата проверява всички мод промени докато скрипта или процедурата свърши и след това се опитва да прати
        колкото се може повече модове към IRC сървърът (ако направите 4х +о, ботът ще ги направи +оооо).
        Синтаксисът е [pushmode <channel> <mode> [parameters]].

        <channel> е каналът за който ще бъде направена промяната.

        <mode> е модът който искате да промените.
        Това може да е нещо за самият канал (като +i или -m) или може да е нещо спрямо потребител в канала (като например +v или
        -о).

        [parameters] са параметрите нужни за промяната на мода.
        Ако слагате или махате ключ на канал например това ще бъде ключът който искате да сложете или да махнете от канала или
        ако давате операторски права на някой това ще бъде неговият псевдоним.

        ВНИМАНИЕ: Можете да направите само ЕДНА промяна на мод чрез командата [pushmode].
        Така че използвайки -оooo за <mode> няма да проработи. Ботът ще направи всичко това след като свърши процедурата.

        Има два начина да изритате някой от канала.
        Да направите това ръчно чрез командата [putserv] или с командата [putkick] която е направена за това.
        Синтаксисът е [putkick <channel> <nickname(s)> [reason]].

        <channel> е каналът от който искате да изритате псевдонима/ите.

        <nickname(s)> са псевдонима/ите които искате да изритате. Това може да бъде или един псевдоним или много разделени с
        запетайки. Колко хора можете да изритате с тази команда зависи от вашият IRC сървър.

        [reason] е причината заради която ги изритвате от канала.

        Сега ще се научите как да изпълнявате команди само при някакви определени условия това също е една от най-важните части,
        почти няма скрипт или програма която да не използва това. С това можете да проверите какво е задал потребителя, да видите
        дали е валидно или да попитате какво да се направи.

        С [if] командата можете да направите скрипта ви да изпълнява дадена команда само когато нещо което сте задали е едно и също
        или различно с друго. Това може да е команда, която да бъде изпълнена 2 стринга, напрактика всичко. Незнаем как да обясним
        това с думи ... но е много проста команда щом я разберете веднъж. Просто ще ви кажем как работи и ще ви дадем няколко примера
        по-късно, за да я разберете по добре.
        Синтаксисът е [if { <action> <compare method> <action>} { <body> }].

        Двете <action> са какво командата [if] трябва да сравни.
        Това може да са 2 стринга, команда (незабравяйте да я обградите в скоби като беше казано) или някакъв текст (заграден в
        кавички, и това също бе казано :)) или всичко друго което може да се използва за сравнение.

        <compare method> казва на [if] командата как да сравни двете actions. Това може да бъде 2 неща, по точно == за 'равно на' или
        != за 'различно от', когато една от <action> не е число.
        Ако и двета <action> са числа можете да използвате и 'по-голямо от' (>) и 'по-малко от' (<) знаци, да видите дали нещо е
        по-голямо от друго (можете да използвате за пример команда която смята колко символа има в <action> и връща числова стойност
        която се сравнява с втория <action>). Накрая но не на последно място, когато сложите 'е' (=) знака след 'е по-голямо от' или
        'е по-малко от' можете да получите 'е по-голямо/по-малко или равно на'.

        <body> е основната команда която ще бъде изпълнена ако [if] командата сполучи.
        Body не трябва да е на една линия, ето защо [if] командата започва с отворена къдрава скоба.
        Можете да сложите нова команда на всеки ред и тя все ще бъде част от [if] командата, докато затворите body с къдрава скоба
        както при процедурата.

        Понякога може да искате да проверите дали нешо е правилно или грешно.
        За компютърната програма 0 винаги значи грешла докато 1 е правилно. Можете да направите [if {$one == 1} { <body> }],
        но има и друг начин да направите това. За да видите дали нещо е правилно можете просто да направите [if {$one} { <body> }]
        и вместо [if {$one == 0} { <body> }] можете да направите [if {!$one} { <body> }]. Можете да замените стринга с команда
        или с каквото и да е друго. Слагайки само един <action> на [if] командата без <compare method> кара TCL да провери дали това
        е вярно. Като се добави ! пред <action> без да се дава параметар за <compare method> и за втори <action> кара TCL да провери
        дали това е грешно. Забележете че в този случай 'вярно' е еквивалентно на всяко число от 0, не само на 1.

        За мачвате на едно или две неща можете да имате няколко условия.
        След вторият action можете да добавите && за 'и' или || за 'или' и да сложите още една проверка. След това можете да направите
        някой неща отново и отново и т.н., но това не означава че ще работи когато използвате и двете && и ||.

        За да предотвратите [if] командата да прави грешки когато види || и && в една и съща [if] команда, можете да ограничите
        частите в които искате && и || да действат като ги заградите в скоби. Не можем да кажем това по по-лесен начин затова ще
        ви дадем пример. Когато имате [if {$test(start) == $test(stop) && $test(when) != "" || $test(what) != ""} { <body> }]
        и искате [if] командата да работи само когато [ $test(start) == $test(stop) ] и [ $test(when) != "" || $test(what) != "" ],
        това вероятно няма да работи.

        [if] командата вероятно ще види това като [ $test(start) == $test(stop) && $test(when) != "" ] или [ $test(what) != "" ].

        Това ще се оправи като сложите последната част м/у скоби което ще го направи да изглежда като:
        [if {$test(start) == $test(stop) && ($test(when) != "" || $test(what) != "")} { <body> }].

        Експериментирайки с това ще е най-добрият начин да разберете как точно работи.

        Възможно е също да сложте втора [if] команда след първата. Това може да се използва ако искате първо да проверите стринг
        А и ако той не отговаря на условието да се провери стринг В.

        Начинът по който може да се направи това е да се сложи [elseif] след затварящата скоба.
        Всичко което идва след [elseif] работи по същият начин по който работи и [if] командата.
        Малък пример:
        if {$nick == "edi"} {
        <first body>
        } elseif {$chan == "#IRCHelp"} {
        <second body>
        }

        В този случай ако $nick съвпадне с "edi" <first body> ще се изпълни.
        Командите в <second body> ще бъдат игнорирани даже и ако $chan съвпадне с "#IRCHelp. Както и да е, ако $nick е различно от
        "edi", но $chan съвпадне с "#IRCHelp" тогава <second body> ще бъде изпълнено. Ако нито един от стринговете не съвпадне
        нито едно от двете ще се изпълни и скриптът ще продължи.

        Можете да сложите колкото искате [elseif] команди. След първата можете да бъде сложена втората и така нататак.

        Освен [elseif] можете да ползвате и [else].
        Body в [else] ще бъде изпълнено след като всички [if] и [elseif] проверки се провалят.
        Можете да използвате [else] без дори да имате [elseif] в вашата [if] команда.
        Ето два малки примера:

        if {$nick=="edi"} {
        (...)
        } elseif {$chan=="#IRCHelp"} {
        (...)
        } elseif {$host != "*![email protected]"} {
        (...)
        } else {
        (...)
        }
        if {$enabled} {
        (...)
        } else {
        (...)
        }


        За разлика от [elseif], [else] може да се използва само веднъж при [if] командата.

        Сега да обърнем внимание как се работи с lists и как да ги разбием на части.

        List е просто казано набор от обекти, за разлика от стирнговете които са набор от символи. Обектът сам по себе си може да
        бъде стринг или друг list с нов набор от обекти. Тези обекти са обикновено разделени с празни места но те могат да
        съдържат и празни места в себе си. Каде обектът в list започва и каде свършва може да бъде дефинирано с отваряща и затваряща
        скоба.

        Командите които ще бъдат дискутирани се отнасят към това което получат за вход като list.
        Това означава че ако входът е нещо което има в себе си скоби, той ще бъде третиран като начало и край на обекта в list,
        така че внимавайте с тези команди когато се занимавате с псевдоними например.

        Ако е нужно ще бъдат добавени и скоби, като например ако имате скоби във това което вкарвате като команда, в този случай
        скобите ще бъдат маркирани като начало и край на обект.

        Примерно ако имахте list "test {foo bar} temp", тогава първият обект от list-а ще бъде "test", втория "foo bar"
        (а не "{foo" и "bar}", защото скобите ще индикират началото и края на обекта) и третият "temp".

        Както беше казано, обектът може да съдържа и нов list с обекти. Това може да ви се стори странно но ще ви дадем пример.
        Ако имахте list "test {foo {foo bar}} temp" тогава "foo {foo bar}" ще бъде вторият обект. Ако искате да го разбиете
        на части отново тогава първият обект ще бъде 'foo' а вторият 'foo bar' и така нататак. Мислете за него сякаш е голяма кутия
        с малки кутии вътре които пък имат в себе си още по-малки кутии. Нещо като принципа на руската матриошка ако знаете какво е
        това ;))

        Lists могат да се съдържат в стринговете, но те могат и да бъдат и изхода на командата.
        Най-важното нещо е да внимавате с командата която използвате и да знаете дали те процедират с това което им пратите като list
        или като стринг и дали те връщат list или стринг, защото ако очакват list трябва да се уверите че обектите вътре са в реда в
        който ги искате и нямат забравени скоби или празни места които ще объркат цялата работа.

        Можете да създадете list с командата
        • .
          Синтаксисът е [list [object(s)]].

          [object(s)] са обектите които искате да има list. Трябва да разделите всеки един обект с празно място и можете да определите
          точно каде обекта започва и завършва с скоби точно както бе казано.
          • командата връща list с обектите които са му били дадени.
            Например [list "test" {foo bar} "temp"] ще върне list в който първият обект е 'test', вторият 'foo bar' а третият 'temp'.

            Вземането на обекти от list е доста лесно. Командата за това е [lindex].
            Синтаксисът е [lindex <list> <number>].


            <list> е list-а от който ще се вземат обектите.
            Това може да е всичко от стринг съдържащ list ($test може да съдържа list например като поставите изхода на
            • командата
              в него чрез [set]) до команди, стига да е валиден списък а не просто стринг.

              <number> е номера на обекта който искате да достигнете.
              Всеки обект в list има свой номер, те започват от 0. Първият обект е 0, вторият 1, третият 2 и така нататак. Малко е странно,
              но ако програмирате това ще ви се стори доста познато.

              Малък пример: [lindex $test 5] връща шестият обект който се намира в $test.

              [lindex] командата връща стринг който съдържа само обекта без отварящи и затварящи скоби които да маркират началото и края
              на обекта ако тези скоби са в list.

              Когато искате да вземете повече от един обект ще смените малко командата. За това ще използваме [lrange].
              Синтаксисът е [lrange <list> <start number> <end number>].

              <list> е list от който ще се вземат обектите също като при командата [lindex].

              <start number> е номерът на обекта от който командата трябва да започне.
              Номерацията на обектите е по същият начин както при [lindex].

              <end number> е номерът на обекта кадето командата трябва да спре.
              Вместо номер да зададете и думата [end]. Това ще накара командата да вземе от даденият първи обект до последният от list.

              Пример: [lrange $test 3 7] връща обектите от 4 до 8 от list който се намира в $test или [lrange $test 4 end] ще върне от
              5-я обект до края на list в $test.

              [lrange] командата връща нов list от обекти които сте избрали, като оставя всяка отваряща и затваряща скоба която маркира
              началото и края на обекта който е бил в list-а и добавя скобите ако е нужно.

              Това може да се направи с [llength] командата.
              Синтаксисът е [llength <list>].

              <list> е листа от който обектите ще бъдат вземани точно както при [lindex].

              Тази команда връща стринг който съдържа номер, който е равен на броя на обектите които list съдържа като се започне от 1
              а 0 ще бъде върната ако list-а е празен.

              Можете и да препокриете обекти от list. За това ще използваме командата [lreplace].
              Синтаксисът е [lreplace <list> <start number> <end number> [object(s)]].

              <list> е листа от който обектите ще бъдат вземани точно както при [lindex].

              <start number> е номерът на обекта от който командата ще започне да препокрива обектите в list. Номерацията е същата както
              при командата [lindex].

              <end number> е номерът на обекта при който командата ще спре да препокрива обектите от list. Вместо номер можете просто да
              напишете [end]. Това ще накара командата replace да препокрие всички обекти от зададеният начален номер до края на list.

              [object(s)] е това s което искате командата да препокрие дадените обекти. Ако не зададете нищо като обект дадените обекти ще
              бъдат изтрити от list. Забележете че само по себе си това е валиден list.

              Пример: [lreplace $test 3 7 "foo" "bar"] връща list с обекти от 4 до 8 препокрити с обектите 'foo' и 'bar' или
              [lreplace $test 4 end] ще върне list с обектите от 5 до края на list изтрити.

              [lreplace] командата връща нов компилиран list с препокритите обекти които вие сте му задали оставяйки отварящите и затварящите
              скоби които маркират началото и краят на обекта, и преди са били в list непокътнати и добавя нови ако е нужно.

              Можете да превърнете стринг в list с командата [split].
              Синтаксисът е [split <string> [character]].

              <string> е стрингът който искате да превърнете, което може да бъде или стринг или изхода на команда който е в вид на стринг.

              [character] е символът който ще бъде използван за разделянето на стринга на обекти. Когато [split] срещне даденият символ
              той ще го види като маркировка за края на обекта и началото на нов. Ако не се зададе символ, символът по подразбиране ще стане
              празното място.

              [split] командата връща нов list в който първият обект е всичко в <string> до [character], вторият обект е всичко м/у
              вторият и третият [character] и т.н. Всяка скоба в <string> ще бъде избегната като се добави нова скоба или наклонена черта.

              Пример: [split "test {foo bar} temp"] ще върне list в който първият обект е 'test' вторият "{foo", а третият "bar}", и
              четвъртият 'temp'. Същото нещо ще върне и [split "test.{foo.bar}.temp" .].

              Сега ще се научим да разделяме стринговете на части.

              Тази команда работи по абсолютно съшият начин както командата [lindex], само че е малко по различна.
              За да вземем символите от стринг ще използваме командата [string index].
              Синтаксисът е [string index <string> <number>].

              <string> е стрингът от който символите ще бъдат взети. Това може да е всичко от стринг както и променлива от команда.

              <number> е номерът от символи който искате да получите, където 0 е първият символ, 1 е вторият, 2 е третият и т.н.

              [string index] командата връща стринг който съдържа символите които вие сте задали. Ако дадете list който съдържа обект
              в скоби, скобите също ще се третират като символи в стринга а не като вимволи за започаване и завършване на обекта.
              Например, [string index "test {foo bar} temp" 5] ще върне "{" а не "f" или "foo bar".

              Тази команда работи по същият начин по които и командата [lrange] с малки разлики. За да получите няколко символа от стринг
              използвайте [string range]. Синтаксисът е [string index <string> <start number> <end number>].

              <string> е стрингът от който символите ще бъдат взети. Това може да бъде всичко от стринг както и променлива от команда.

              <start number> е номерът от който искате да започнете, където 0 е първият символ, вторият 1 и т.н.

              <end number> е крайният номер до който искате да достигнете, където 0 е първият символ, вторият 1 и т.н.
              Тук можете да използвате 'end' за да зададете че искате да вземете всичко от началният номер до края на стринга.

              [string range] командата връща стринг. Ако дадете list който съдържа обект в скоби, скобите ще бъдат третирани като символи
              в стринг, а не като специални символи за началото и края на обекта. Например, [string range "test {foo bar} temp" 5 8] ше
              върне "{foo" а не "foo ".

              Ако искате да видите колко символа има даденият стринг използвайте командата [string length].
              Синтаксисът е [string length <string>].

              <string> е стрингът от който искате символите да бъдат взети. Това може да бъде всичко от стринг както и променлива от команда.

              [string length] командата обръща стринг който съдържа номер равен на броят символи които стринга съдържа. Ако дадете list който съдържа обект в скоби, скобите ще бъдат третирани като символи
              в стринг, а не като специални символи за началото и края на обекта. Например, [string length "test {foo bar} temp"] ше
              върне 19 + скобите а не 17.

              В някой случаи ще искате да видите дали част от текст се съдържа в стринг. Можете да видите това с командата [string match].
              Синтаксисът е [string match <pattern> <string>].

              <pattern> е това за което искате да бъде търсено.
              Освен нормални символи можете да сложите и звездичка (*) или въпросителен знак. * означава че всичко ще бъде съвпадне, а ?
              само с един символ. Например ако имате "*foo*" за <pattern> [string match] ще намери съвпадение в "foo" навсякаде в стринга,
              така че ако търсим "*foo*" в "test foobar" ще имаме съвпадение. Ако тук използвате "?foo*" ще намери съвпадение само ако
              стринга има символите 'foo' от второто място до петото независимо от наставките, така че ако търсим "?foo*" в "test foobar"
              няма да имаме съвпадение но "*foobar" ще съвпадне.

              <string> е стринг в който [string match] ще търси <pattern>. Това може да бъде всичко от променлива до команда която връща
              стринг.

              [string match] връща 1 ако намери съвпадение и 0 ако не намери.

              Много неща в TCL правят разлика м/у малки и големи букви. Например в много случаи 'FOO' няма да бъде същото както 'foo',
              така че в някой случаи ще бъде по добре да превърнете всичко в малки или в големи букви преди да го използвате. Това може да
              бъде направено с командите [string tolower] и [string toupper]. Синтаксисът е [string <tolower/toupper> <string>].

              <tolower/toupper> е в какво искате да превърнете стринга, [tolower] ше го направи на малки а [toupper] на големи.

              <string> е стринга който искате да превърнете. Това може да бъде всичко от променлива до команда която връща
              стринг.

              [string <tolower/toupper>] командата връща стринг в който всички символи са само малки или големи букви. Ако зададете list
              който съдържа обекти в които има скоби те също ще бъдат сметнати за символи в стринг а не като специални символи за край и
              начало на обект. Например, [string tolower "test {foo BAR} temp"] ще върне "test {foo bar} temp" а не "test foo bar temp".

              Можете да превърнете list в стринг с командата [join].
              Синтаксисът е [join <list> [character]].

              <list> е list , който искате да превърнете в стринг, което може да е всичко от сринг, който съдържа list или
              команда, която връща list например.

              [character] е символът който ще бъде сложен м/у обектите от list в новият стринг. Ако не сте задали символ ще бъде използвано
              празно място.

              [join] командата връща стринг с всички обекти от <list> разделени с [character].
              Всяка скоба която е в <list> няма да бъде всключена в новият стринг, само обектите ще бъдат сложени в стринга.

              Пример: [join [list "test" {foo bar} "temp"]] ще върне стринг съдържащ "test foo bar temp" а [join [list "test" {foo bar} "temp"] .]
              ще върне "test.foo bar.temp" (забележете че празното място на 'foo bar' НЕ е препокрито с . от командата [join] защото тя
              свързва _обектите_ от list а не думите!).


              Сега ще научим различните видови цикли (loops).
              При повечето случаи може да ви се стори доста полезно да накарате скрипта ви да повтори някоя команда няколко пъти, защото
              често нямате контрол над това колко големи са нещата и поради тази прична една команда трябва да бъде повторена.

              Най-простият цикъл е [while].
              Това ще продължи докато дадено действие е вярно.
              [while] командата доста прилича на [if] командата. Синтаксисът е [while { <check> } { <body> }].

              <check> работи по абсолютно същият начин като [if]. Възможно е да замените 'while' с 'if' и да накарате скрипта да извърши
              командата само веднъж без да се натъкне на някакви грешки освен на тези които идват от вашият скрипт но не и от самата [while]
              командата.

              <body> е същото като при [if].

              Пример:
              set test "[chanlist #IRCHelp]"
              set ops 0
              while {$test != ""} {
              if {[isop [lindex $test 0] #IRCHelp]} {
              incr ops
              }
              set test "[lreplace $test 0 0]"
              }
              puthelp "PRIVMSG #IRCHelp :There are currently $ops people opped in #IRCHelp."

              Друг цикъл е [foreach].
              В този цикъл слагате един или повече lists и след това команди които ще бъдат изпълнени за всеки обект от list.
              Синтаксисът е [foreach <string> <list> [<second string> <second list> ...] { <body> }].

              <string> е стринга в който ще бъде сложен обекта. Можете да сложите колкото си искате lists в цикъла, само да има стринг в
              който да се слагат обектите. Също защото foreach знае че става въпрос за стрингове няма нужда да слагате $ отпред.
              <string> ще съдържа обект от list се едно [lindex] е използван.

              <list> е list от който цикълът трябва да вземе обектите.

              <body> е командите които ще бъдат изпълнени и работи по същият начин както при [while].

              Ето пример как работи [foreach]:
              set ops 0
              foreach nickname [chanlist #IRCHelp] {
              if {[isop $nickname #IRCHelp]} {
              incr ops
              }
              }
              puthelp "PRIVMSG #IRCHelp :There are currently $ops people opped in #IRCHelp."

              Третият и последен цикъл е [for].
              Този цикъл е горе-долу лесен и се използва най-вече когато някой иска да цикли нещо за период от време.
              Синтаксисът е [for { <start> } { <check> } { <loop> } { <body> }].

              <start> е командата която ще бъде изпълнена преди цикълът да се стартира.
              Това може да е дефинирането на стринг на 0.

              <check> е проверката която ще бъде направена докато цикълът върви и работи по същият начин по който работи и [while].

              <loop> е командата която искате да бъде изпълнена всеки път когато цикълът свърши. Това може да бъде увеличаването на стринг
              с 1.

              Пример:
              set test "[chanlist #IRCHelp]"
              set ops 0
              for { set number 0 } { $number < [llength $test] } { incr number } {
              if {[isop [lindex $test $number] #IRCHelp]} {
              incr ops
              }
              }
              puthelp "PRIVMSG #IRCHelp :There are currently $ops people opped in #IRCHelp."

              Чудили ли сте се някога какво значат тези странни символи ((?:[a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}). Това са просто регуларни изрази, и не са никак сложни щом ги разберете веднъж. Команда с която можете да използвате регуларни изрази за да намерите съвпадение в стринг е [regexp]. Главният синтаксис на командата е [regexp <регуларен израз> стринг]. Ако имаме съвпадение командата ще върне 1 в противен случай 0, ако се зададе -inline опцията (преди регуларният израз) ще се върне съвпадението. Самите регуларни изрази ще обясним малко по късно, сега да поговорим малко за самата команда. Ако се зададат допълнителни аргументи след стринга то тогава в първият от тях ще се съдържа всичките символи от стринга които са съвпаднали с регуларният израз, а следващите елементи ще съдържат първият елемент после вторият и така нататак... Могат и да се зададат както споменахме за -inline и допълнителни опции преди регуларният израз. Сега ще споменем само най-важните от тях:


              -about Вместо да се прави съвпадение с регуларният израз ще върне list който съдържа информация за регуларният израз. Използва се за debug за повече информация вижте man страницата.



              -expanded Използване на резширените регуларни изрази кадето празните места и коментарите се игнорират, същото като (?x) и както /x при perl ;).



              -indices Вместо да се слага в вторите, третите и т.н. аргименти след стринга, съвпаденията ще се прави list съдържащ два елемента които ще са индексите кадето има съвпадение.


              -line Включва правенето на разлика на символа за нов ред (\n), по принцип новата линия е съвсем нормален символ без специално значение. С флага, `[^` и '.' никога няма да имате съвпадение с това. `^` съвпада с празен стринг след нова линия в допълнение на нормалната му функция, и '$' съвпада с празен символ в допълнение на нормалната му функция.
              Този флаг е еквивалентен на двете функции -linestop и -lineanchor, или на опцията (?n).


              -linestop Това променя държанието на `[^` и '.' така че те да спират на новата линия. Това е също (?p).



              -lineanchor Това променя държанието на `^` и '$' (котвата) така че те да означават началото и края на линията. Същото като (?w).


              -nocase Прави големите букви в стринга на малки докато се търси съвпадение.


              -all Прави така че регуларният израз да съвпадне колкото се може повече пъти в стринга. Като връща целият брой на съвпаденията.


              -inline За това можем да дадем един пример, мисля че го обяснихме по-горе:

              regexp -inline -- {\w(\w)} " inlined "
              => {in n}
              regexp -all -inline -- {\w(\w)} "
              inlined "
              => {in n li i ne e}


              -start index Определя се от каде да започне търсенето. Използвайки `^`,няма да има съвпадения с началото на линията, но \A все още ще се използва за началото на стринга.


              -- Индикира края на опциите. Всичко след това ще бъде третирано като регуларен израз нищо че започва с тиренце.

              Ако зададете повече стрингове за да видите съвпаденията те просто ще бъдат напулнени с -1, ако сте задали -indicies или ще бъдат празни.

              Сега дойде времето за същинската част - епа как да го направим това регуларния израз и яде ли се, щото излгежда много сложно, некфи чертички и такива работи :P

              Регуларните изрази в TCL sa написани от Хенри Спенсър, и са базирани на perl5.


              Примерно ако искате да видите дали има символ М в стринга се пище М на мястото на регуларният израз ;)). Ако искате да видите дали има две съвпдения можете да използвате ММ което ще подразни разбирачите на регуларни изрази които биха го написали M{2} така изглежда доста по добре нали ? ;І Ако искате да следите за примерно 3 или повече (повечето могат да ви потрябват ако използвате -inline или по някакъв начин вкарвате съвпадението в стринг за по късно обработване) използвайте М{3,} ако след запетайката напишете число по голямо (ТРЯБВА да е по голямо от предхождащото го число) то тогава на български това би прозвучало така 'Искам 3 съвпадения или повече ненадхвърляйки Х, кадето Х е числото за което ставаше дума.' Пример:
              M{0,1} това ще съвпадне с 0 или 1 съвпадения, което е абсолютно същото с ?-я знак, тоест M? . Ето и още няколко дефинирани за наше улеснение подобна група от символи: * - {0,} съвпада с 0 или с много символи; + - {1,) съвпада с 1 или повече символи.

              Звездичката и плюса (както и {m,}) са лакоми което ще рече че ще направят колкото се може повече съвпадения. Ако искате да го направите колкото се може по-малко съвпадения, трябва да сложите '?' нещо като: *? +? {m,}? {m,n}?

              Тези съвпадения се правят само за един символ, ако искате да бъдат направени за повече от един трябва да ги заградите в скоби. Пример: (qwerty)+, ще вземе колкото се може съвпадения с qwerty, които следват едни след други. Тоест qwertyqwertyqwerty123787324qwerty ще съвпадне с първите 3 qwerty-та и после с последното.

              Щом група от символи се заградят в скоби, те биват върнати като съвпадение, в противен случай няма да бъдат върнати. Ако искате просто да имате групиране без това групиране да се върне като част от съвпадението използвайте (?:chars).

              Група от символи заградени в [] скоби ще се смята като един символ който може да бъде едно от тези неща в скобите. Тези символи могат да обхващат и диапазон от символи (A-Z - ABCD...Z ,a-z - abcd...z ,0-9 - 0123456789. Ако скобите започват с '^' тоест '[^' това означава всички символи които НЕ са ... Ако искате да имате съвпадение с '^' то тогава не трябва да я слагате в началото, а на всяко друго място но не и там или да я \!!! Не можете да си правите несъществиващи диапазони, ако искате да имате съвпадение с '-' можете да го сложите в началото или в края на скобите, не можете да правите и няколко диапазона слепени примерно A-B-G но можете да направите A-Za-z.

              Ако скобите започват и завършват с точка (.) тогава това което е в тях няма да се счита като поредица от символи а като един общ символ, примерно [.ab.] ще съвпадне с ab но не и с a.

              Точката (.) <- ще сувпадне с всеки символ но не и на новият ред. Примерно f.*bar в foobar ще съвпадне с двете о-та, но ако имаме perlprexer и напишем p.*e ще съвпадне с erlprex а не с erlpr защото * е лакома както казахме по-горе.


              Ако искте да имате съвпадение в началото на реда използвайте '^' , а за ограничител за края на реда '$'. Позитивното гледане напред се прави чрез (?=char), а негативно (?!char) ето няколко примера за да ви стане ясно:
              Имате foobar и изкате да има съвпадение с foo последван от bar използвайте foo(?=bar)
              имате IRCGame и искате да имате съвпадение с IRC което не е полседвано от Help тогава използвайте IRC(?!Help)
              и в двата примера ще има съвпадения. Регуларните изрази не могат да завършват с наклонена черта (\).

              Има няколко специални символа в регуларните изрази които могат да се използват направо (наготово). Те групират няколко символа. Сега ще ви дадем една голяма част от тях, те се използват като най-нормални символи в регуларен израз:

              \a символът камбанка както в C

              \b едно назад (две напред - just kidding kiddies) backspace, както в C

              \e `ESC', или окталната стойност 033

              \f formfeed, както в Perl

              \n newline, както при Perl

              \r carriage return, както при Perl

              \t horizontal tab, както при Perl

              \uwxyz
              (кадето wxyz са точно четори hexadecimal цифри) е Unicode символа U+wxyz

              \Ustuvwxyz
              (където stuvwxyz са точно осем hexadecimal цифри) запазени за някакви хипотетични Unicode екстензии за 32 бита.

              \v vertical tab, както навсякаде

              \0 символа която стойност е 0

              \xyz (където xyz е точно 3 октални цифри) символите чиито октална стойност е 0xyz.

              Hexadecimal цифри са `0'-`9', `a'-`f', и `A'-`F'.
              Octal цифри са `0'-`7'.


              *Малко съкращения за мързелите*
              \d - поредица от всички цифри - [0-9]

              \s - знак за интервал - табулация, интервал новред или връщане - [ \t\n\r]

              \w - знак за дума - [A-Za-z_]

              \D - обратното на \d - [^0-9]

              \S - обратното на \s - [^ \t\n\r]

              \W - обратното на \w - [^A-Za-z_]


              Забележете че тези символи могат да се използват и в '[ ]'.


              \A съвпадение само в началото на стринга

              \m само в началото на думата

              \M само в края на думата

              \y в началото или в края на думата

              \Y да не е началото или края на думата

              \Z съвпадение само в края на стринга

              \m (където m е цифра) ще споменем след малко

              \m ще съвпадне с същото което е съвпаднало при мачването на стринга което е заградено в скоби, малко сложничко затова един пример ще ви дойде добре ([abc])\1 това ще съвпадне с два еднакви символа или aa или bb или cc.

              В допулнение на главният синтаксис има няколко специални форми. Примерно ако се започне с поредица (?xyz) кадето xyz са една или повече буквени символи дава определени указания на регуларният израз, сега ще кажем някой от тях:

              c разлика м/у малки и големи букви (по-принцип е включ.)

              i прави разлика м/у малки и големи букви

              m изторически символ за n

              n прави разлика за нов ред

              p частична разлика за нов ред

              s никаква разлика за нов ред (по-принцип е включ.)

              t малък синтаксис (по-принцип)

              x увеличин синтаксис

              Когато използвате увеличеният синтаксис, празните места и коментарите ще бъдат игнорирани (това вече бе казано) можете да избегнете това като поставите \ пред тях.

              Можете да имате няколко регуларни израза разделенио с '|' като всеки регуларен израз е обграден в () или в (?:).


              Друга команда която използва регуларните изрази е regsub. Тя прави заместване на част от стринга с нещо друго. Синтаксиса е
              [regsub regexp string substspec varName].

              Прави се съвпадение на регуларният израз в стринга замествайки съвпадението със 'substspec' и копирайки новият стринг в 'varName'. Ако 'substspec' съдържа '&' или '\0', тогава това ще бъде заместено с съвпадналата част от регуларният израз.
              Ако 'substspec' има '\n' кадето n е цифра м/у 1 и 9, тогава това ще бъде заменено с n съвпадението оградено в скоби.

              Можете да сложите допулнително наклонени черти (\) за да избегнете &, \0, \n или \. Допълнителни опции могат да бъдат зададени като преди регуларният израз се добавят една от:

              -all Всички съвпадения в стринга се заместват, иначе само първото съвпадение ще бъде замесено.


              -expanded Можете да използвате разширени регуларни изрази.


              -line Прави разлика м/у новата линия (това вече бе обяснено, като говорихме за regexp).

              -linestop Сменя държанието на '[^' и '.' (това вече бе обяснено, като говорихме за regexp).


              -lineanchor Сменя държанието на `^' и `$' (това вече бе обяснено, като говорихме за regexp).


              -nocase Големите букви ще бъдат направени на малки. (това вече бе обяснено, като говорихме за regexp).

              -start index Определя се от каде да започне търсенето. Използвайки `^`,няма да има съвпадения с началото на линията, но \A все още ще се използва за началото на стринга.

              -- Индикира края на опциите. Всичко след това ще бъде третирано като регуларен израз нищо че започва с тиренце.

              Командата връща колко пъти са били направени замествания.

              Има няколко начина които се иползват монякога за да се избегнат проблемите с специалните символи в TCL. По-точно някой скриптове филтрират входа с нещо като:

              proc filt {data} {
              regsub -all -- \\\\ $data \\\\\\\\ data
              regsub -all -- \\\[ $data \\\\\[ data
              regsub -all -- \\\] $data \\\\\] data
              regsub -all -- \\\} $data \\\\\} data
              regsub -all -- \\\{ $data \\\\\{ data
              regsub -all -- \\\" $data \\\\\" data
              return $data
              }

              Такъв скрипт може да премахне проблемите с специалните символи които могат да се получат при зле написани скриптове. Но дали ще го направи или не зависи от детайлите на скрипта. Може да не ви реши проблема или само частично. Стринга в който искате да бъдат избегнати специалните символи трябва да бъде маниполиран така:
              set string [filt $string]

              Сега е време да поработим малко с файлове. Това ще е малко по-трудничко но с тях ще можете да запазите информацията си даже и
              след рестартиране на бота.

              Преди да използвате файл трябва да го отворите. Това става с командата [open].
              Синтаксисът е [open <filename> [access]].

              <filename> е името на файла който искате да отворите.

              [access] е какво искате да направите с файла.

              Ето списък с различните access типове според ман страницатa:

              r Отваря файл само за четене; файлът трябва да съществува.
              Това е стойноста по подразбиране ако не се зададе такава.

              r+ Отваря файл за четене и писане; файлът трябва да съществува.

              w Отваря файл само за писане. Създава го ако не съществува,
              в противен случай изтрива всичко което има в него.

              w+ Отваря файл за писане и четене. Създава го ако не съществува,
              в противен случай изтрива всичко което има в него.

              a Отваря файл само за писане. Файлът трябва да съществува,
              и информацията се пише в края на файла.

              a+ Отваря файл за зачетене и писане. Ако файлът не съществува,
              той просто се създава. Ако вече е създаден се пише в края на файла.

              [open] командата връща така нареченият канал.
              Този канал ще ви потрябва ако искате да правите нещо с файла, така че трябва да 'хванете' този канал
              това може да бъде направено като каналът отиде в стринг. Пример за това е следният код в който каналът на отвореният $file
              ще се запази в $fs:
              set fs [open $file r]

              След като свършите работата си с файла трябва да го затворите.
              Затварянето е точно след писането и четенето, затова ще дадем по-добри и по-пълни примери по-късно, все пак какъв е смисала
              да отворим и затворим файл без да сме направили нищо с него нали ?!;П) Можете да затворите канал с [close].
              Синтаксисът е [close <channel>].

              <channel> е каналът в който файлът е хванат с [open].

              След като сте затворили файл трябва да го отворите наново за да можете да четете и пишете от него.

              Можете да четете от файл или линия по линия или парче по парче.
              С [gets] командата можете да четете файла линия по линия. Синтаксисът е [gets <channel> [string]].

              <channel> е каналът в който файлът е хванат с [open].

              [string] е стрингът в който ще бъде сложена линията която е взета. Ако зададете стринг gets командата ще върне колко символа
              е имала линията и ще сложи линията в стринга. Ако не зададете стринг ще се върне линията.

              Пример:
              set fs [open $file r]
              gets $fs line(first)
              gets $fs line(second)
              close $fs

              Това ще сложи първата линия от $file в $line(first) а втората от $file в $line(second).
              Можете да прочетете изхода на команда използвайки pipe и помандата open това става по долу-горе следният начин:

              set fs [open "| nslookup" r]
              puts $fs "irchelp.unibg.org"
              close $fs

              Ако искате да пишете към някаква команда можете да използвате отново pipe:

              set fs [open "|cat >> file" w]
              puts $fs "one line"
              puts $fs "two lines"
              puts $fs "three lines"
              close $fs

              Можете да четете файла парче по парче с командата [read].
              Синтаксисът е [read <channel> [bytes]].

              <channel> е каналът в който файлът е хванат с [open].

              [bytes] са номерата в байтове които искате да прочетете от файл.
              Ако не зададете номера в байтове целият файл ще бъде прочете,

              Пример:
              set fs [open $file r]
              set info [read $fs 10]
              close $fs

              Това ще сложи първите 10 байта от $file в $info.

              Можете да пишете в файлове с командата [puts].
              Синтаксисът е [puts <channel> <text>].


              <channel> е каналът в който файлът е хванат с [open].

              <text> е това което искате да напишете в файла.

              Пример:
              set fs [open $file w]
              puts $fs "$nick"
              close $fs

              Това ше напише $nick в $file.

              В някой случаи може да не знаете колко е голям файла и заради това да не знаете до каде да четете от файла.
              С [eof] командата можете да разберете дали това е краят на файла. Синтаксисът е [eof <channel>].

              <channel> е каналът в който файлът е хванат с [open].

              [eof] командата връща 1 ако последната команда която е работила с канала е върнала "end of file" и 0 ако не е.

              Един от начините да използвате [eof] командата е в [while] цикъл.
              set found 0
              set fs [open $file r]
              while {![eof $fs]} {
              gets $fs line
              if {$line == $nick} { set found 1 }
              }
              close $fs
              if {$found} {
              putdcc $idx "$nick was found!"
              } else {
              putdcc $idx "$nick was not found."
              }

              Това ще провери всяка линия от $file и ще ви каже дали тази линия е еквивалента на $nick.

              Ако работите с файлове трябва да знаете как да проверявате дали съществуват, иначе ще трябва да създавате нов файл всеки път
              когато стартирате TCL скрипта си, защото в противен случай скрипта ви ще даде грешка ако се опитате да отворите несъществуващ
              файл. Това може да бъде направено с командата [file exists]. Синтаксисът е [file exists <filename>].

              <filename> е файлът който искате да проверите.
              Забележете че патечката в която всички команди или файлове се изпълняват е директорията кадето е binary-то на бота, така че
              ако решите да пишете извън eggdrop директорията трябва да зададете целият път в <filename>.

              [file exists] командата връща 1 ако файла съществува и 0 ако не.

              Ако незнаете какво е сокет спокойно можете да прескочите тази глава ;)))
              Зараждането на модул е ненужно, използва се [socket options host port] командата.
              Тя връща сокет, който може да се използва за по-късно сега да обясним малко опциите, които можете да използвате при отварянето на сокета.

              най-лесното

              set sock [socket 127.0.0.1 21]

              Което прави канал $sock.

              Ако искате да асинхронизирате връзката използвайте -async. Това означава че сокета ще се направи веднага, но няма да се свърже веднага с сървъра. Това не се препоръчва при писането на TCL-и за egg.

              set sock [socket -async 127.0.0.1 21]

              В случай че искате да използвате за връзка не локалния си адрес а друг от вашата машина пробвайте -myaddr

              set sock [socket -myaddr 12.35.61.1 127.0.0.1 21]

              За да пишете към сокета използвайте познатата функция puts channel

              puts $sock "user edi"
              flush $sock
              puts $sock "pass edolino"
              flush $sock
              puts $sock "QUIT"
              flush $sock

              така ще се логнете на сървъра и ще излезете от него (s u: edi, p: edolino).
              flush се използва за да flush-не всяка буферирана output информация
              Всяка информация която е вързана се пише в $sock, за да я извлечете използвайте gets channel

              set line [gets $sock]

              $line ще съдържа първата линия върната от сокета (обикновено 220 ProFTPD 1.2.5 Server (ProFTPD Default Installation) [irchelp.unibg.org])

              За четене само на част от информацията използвайте [read chan numchars], например:

              set first20chars [read $sock 20]

              Това ще вземе първите 20 символа върнати от $sock.
              За да затворите канала използвайте close $sock.

              Можете да използвате и fconfigure за да се настрои сокет канала върнат от socket командата.
              fconfigure с -error ще върне върне грешка при връзката с сокета. Хубавото е да ползвате това когато използвате -async, за да разберете дали имате успех.

              set returned [fconfigure $sock -error]

              Това ще върне "" ако всичко е ок, иначе ще върне грешка.

              set arr [fconfigure $sock -sockname]

              ще върне списък с 3 елемента (адреса на сокет-а, хост-а на сокет-а и порт-а на сокета). Ако хост name-а не може да се resolv ще се върне същото като адреса.

              set arr [fconfigure $sock -peername]

              пак връща 3 ел. но само за client socket -> address, хост и порт към който сокета се е вързал, отново ако хост name-а не може да се resolv ще се върне същото като адреса.

              Има и сървър връзка, ако ви интересува повече по въпроса `man n socket`.

              Сега ще засегнем малко темата за връзка с http сървъри, решихме само да кажем основното, а по късно вече можете да усъвърщемствате наученото.

              Най-важното нещо е да имате http модула на TCL можете да го вземете от http://irchelp.unibg.org/irchelp/Downlo ... tpd.tcl.gz, след това първъят ред трябва ВИНАГИ да е:

              package require http

              което означава че се изсиква модула http.

              http::config -accept "image/gif, "image/jpeg, text/*"

              С тази опция можете да зададете какви файлове могат да бъдат приети,
              по-принцип се приемат */* (всички), тази опция надали би ви помогнала много...

              http::config -proxyhost "proxy.beem.com" -proxyport 8080

              С това можете да минете през proxy сървър (proxy.beem.com), което е на порт 8080.

              Кой аксесва сайта ви? (Mozzila/5.0):

              http::config -useragent "Mozilla/5.0"

              По-принцип е "Tcl http client package 2.2."
              За да се смъкнете файл просто използвайте

              set token [http::geturl http://127.0.0.1/manual/index.html]
              set var [http::data $token]

              Което ще смъкне от http://127.0.0.1/manual/ файла index.html и ще го постави в $var (първо се слага в специална променлива за модула и после се преработва в четим вид чрез http::data). Ако искате да свалите файла в bin мод (по-принцип това се детектва по подразбиране) използвайте

              set token [http::geturl http://127.0.0.1/manual/index.html -binary 1]

              Ако искате да добавите допулнителен header изплзвайте

              set token [http::geturl http://127.0.0.1/manual/index.html -headers "My Header here!"]

              За да изпълните POST query:

              set token [http::geturl http://127.0.0.1/manual/index.html -query query]

              Timeout-a се определя от

              set token [http::geturl http://127.0.0.1/manual/index.html -timeout 100]

              Token-а бива рестартиран чрез:

              http::reset token

              както бе казано http::data token враща четима информация от http::geturl

              Използвайте

              ::http::status token

              да видите ефекта от използването на token-a

              За https използвайте или http::register, или LibCurl който върви отеделно от TCL (затова решихме да не пишем за него) и може да бъде взет от http:///irchelp.unibg.org/irchelp/Downloads/curl.zip .

              ::http::register протокол порт команда

              Протокола примерно е https, порт-а който използва протокола, и команда е командата която ще бъде изпълнена от TCL за да се създаде сокет пример ::tcl::socket, но тя изисква tls да бъде инсталиран, така че внимавайте! Ето и малък пример:

              package require http ;# зарежда http модула

              package require tls ;# зарежда tls

              http::register https 443 ::tls::socket ;# регистрира използването на https на порт 443
              set token [http::geturl https://my.secure.site/] ;# взема информация от сайта my.secure.site/

              За да изключите използването на https използвайте

              ::http::unregister протокол

              Пример:
              http::unregister https

              Да обърнем внимание малко и на грешките:

              http::geturl ще изкара грешка ако:

              дадете грешна команда, URL, host или URL на грешен порт.

              Това означава че то не може дори и да започне прехвърлянето на данни. Ако се получи грешка при I/O сокета при четенето също ще има грешка. След подобни неща се използва ::http::cleanup token. Ако не се получи грешка няма да има проблем. Но ако искате да проверите какво е станало можете да го направите с ::http::status token иначе можете да използвате ::http::error
              за да видите цялата грешка, status може да върне:

              ok - ако всичко е добре, все пак трябва да проверите http::code token или http::ncode token

              Това е ако се върне нещо като "HTTP 404 File not found", то не е грешка, а е върнат код, който може да бъде проверен с тези команди.

              eof - ако сървърът е затворил сокет-а, без да върне грешка
              error - ако сървърът е върнал error съобщение

              Като за последно малко да ви объркаме :))

              token може да бъде превърн в масив с

              upvar #0 $token state

              този масив ще съдържа елементите:

              state(body) - съдържанието на URL-то
              state(charset) - charset-а използван iso8859-1
              state(coding) - част от Content-Encoding meta-data променливата
              state(currentsize) - колко байтове са взето от URL-то
              state(error) - грешката, ако има такава при получаването на URL-то
              state(http) - HTTP statusa върнат от сървъра.
              state(meta) - meta елементите
              state(posterror) - грешка получена докато е писана POST заявката
              state(status) - или 'ok' за добре свършена работа, timeout, ако е имало timeout, reset, ако е имало user-reset, или error при грешка
              state(totalsize) - копие от Content-Length meta-data-та
              state(type) - копие от Content-Type meta-data-та
              state(url) - взето URL

              Бъдете внимателни когато използвате http с Eggdrop, защото Eggdrop спира когато има заявки което може да доведе до доста проблеми с управлението на бота и канала.

              Като цяло това е http.


              Сега ще обсъдъм разни тактики за писането на скриптове които могат да ви се сторят доста полезни и които могат да ви потрябват.

              За феновете на mySQL има специални модули за връзка с TCL->MySQL както за *NIX така и за Windows и Solaris. Можете да ги разгледате към тях върви и достатачно допълнителна информация.

              http://irchelp.unibg.org/irchelp/Downlo ... /fbsql.zip
              http://irchelp.unibg.org/irchelp/Downlo ... 0.9.tar.gz

              Главната идея за изплзването на MySQL е статистиките да бъдат на MySQL, което ще улесни вашата работа. А като стана дума за статистики и не ви се занимава с MySQL можете да използвате доста добри TCL скриптове както и модули... хвърлете едно око над http://irchelp.unibg.org/irchelp/IRC/Eggdrop.htm

              Много хора зареждат тоново скриптове наведнъж, и не искат да имат проблеми !!! Има няколко начина които могат да решат проблемите. Използвайте колкото се може по _малко_ return 0 или в противен случай ще спре всички bind търсения преди процедурата ви.. Ето някой идеи:
              1. Наименувайте proc-а си смислено.
              proc mbti:antiidle {} {}

              НЕ нещо от сорта на:
              proc script {} {}

              2. Същото се отнася и за променливите ви. Ако използвате '-' в тях когато ги викате ги обграждайте в скоби така -> ${mbti-antiidle}

              3. Ако скриптът ви използва таймери гледайте да не са много.

              Можете да накарате скрипта ви да изпълни някаква команда след определен период от време в минути или секунди. Това може
              да бъде направено с таймер с командите [timer] и [utimer].
              Синтаксисът е [timer <time> "<command> [parameters]"].

              <time> е след колко време командата ще бъде извършена.
              [timer] изисква това в минути а [utimer] в секунди.

              <command> е командата която ще бъде изпълнена. Това може да бъде TCL команда, Eggdrop команда или всичко друго стига то да е
              валидна команда.

              [parameters] са параметрите които искате да дадете към командата.

              С командите за [timers] и [utimers] можете да видите списък с текущите таймери. Тези команди не изискват никакви параметри
              и връща лист всеки обект от който съдържа информация за един от таймерите който върви в момента.

              Забележете че ако в таймера имаме $foo който съдържа примерно "[foo]" и след това извикаме таймера с [utimer 30 "test $foo"]
              ще се опита да изпълни командата 'foo' защото е заградена в скоби и изпраща изхода на командата към 'foo' а не това което е
              върнала командата. Така че бъдете много внимателни когато използвате таймери и избягвайте всяка скоба в стринга си с команда
              като
              • или като слагате наклонени черти пред скобите в стринга нещо като [set foo "\\\[foo\\\]"] което ще даде на $foo
                стойноста "\[foo\]".

                Поради тази причина синтаксисът на командата [timer] е добре да бъде [timer <time> [list <command> <parameters>]"] когато
                изпращате параметри към процедура за да предотвратите грешките които могат да се получат.

                Можете да получите радном числа с [rand] командата. Синтаксисът е [rand <number>].

                <number> е възможните номера от които искате [rand] да връща номер.
                Ако искате 2 възможности трябва да използвате [rand 2], но [rand] започва да брои от нула така че това ще върне или 0 или 1.
                Затова [rand] връща рандом номер м/у 0 и (<number> - 1).

                Например [rand 10] ще върне рандом номер м/у 0 и 9.

                Когато се опитвате да достигнете до стринг който не съществува TCL ще ви даде грешка, затова проверката дали стринга съществува
                е предимство. Това може да бъде направено с [info exists]. Синтаксисът е [info exists <string>].

                <string> е името на стринга който искате да промените. Ако стринг е масив можете или да проверите дали самият масив съществува
                или да проверите дали даден стринг от него съществува, така че и двете 'test' за масива и 'test(what)' за стринга 'what' от
                масива 'test' са валидни проверки.

                [info exists] командата връща 1 ако стрингът съществъва и 0 ако не.
                Например, ако направите [set test(foo) "bar"] и ако използвате [info exists test] то ще върне 1 и [info exists test(foo)]
                също ще върне 1.

                Вече знаете какво е [incr] но понякога бихте искали да направите малко по сложни математически операции, можете да ги направите
                с командата [expr]. Синтаксисът е [expr <calculation>].

                <calculation> е това което искате да сметнете.
                Можете да смятате колкото си искате дълги работи. Нормалните компютърни символи са валидни, които са +/- * (за умножение),
                / (за деление) и % (за деление с остатък). [expr] командата смята дадените <calculation> по официялният начин което значи че
                * и / имат по големи привилегии от +/-.

                [expr] може да прави доста други неща но няма да дискутираме това сега. Можете да намерите повече за това на ман страницата.
                Също така забележете че [expr] командата работи като [timer] и [utimer], затова трябва да избягвате скоби.

                Ботът има някой pre-set глобални променливи, като името на бота ($botnick).
                Можете да ги намерите в tcl-commands.doc.

                botnick
                # псевдонимът който ползва бота.

                botname
                # nick!user@host който сървърът вижда, пример 'Valis![email protected]'

                server
                # сървърът на който е бота в момента, пример 'irc.UniBG.oRG:6667'

                version
                # версията на бота (пример: "1.6.12+pl1 1010201 pl1");
                # първото е версията на бота, второто нумерик стойноста и, третото пачовете които са добавяни.

                uptime
                # unixtime стойноста от кога е пуснат бота

                # за да ги използвате в proc, трябва да ги декларирате като глобални в началото на proc-а си (global botnick)

                Възможно е да декорирате малко вашият текст.
                Както бе споменато за специалният код който подчертаваше текста ви. Освен да го подчераете можете да го оцветите или удебелите.
                Използвайте тези кодове като ги слоците м/у текста който искате да декорирате.

                Кодът за подчертаване е \037 (или \031), кодът за удебеляване \002, кодът за дветовете е \003 и след това добавяте номерът на
                цвета, а кодът за reverse е \022. Най-новата версия на mIRC има pop-up прозорче което се показва когато натиснете CTRL+K, за
                да напишете нещо цветно. Цветовете в това прозорче са същитя както в TCL.

                Започвате и свършвате мястото кадето искате да декорацията да започне и да спре, със същият код с който сте я започнали.
                Пример е "Hello \002$nick\002, welcome in $chan." което ще одебели само '$nick' а "Hello \002\0034$nick\003\002, welcome in \037$chan\037."
                ще одебели и оцвети '$nick' в червен цвят а '$chan' го подчертава.
                Забележете че когато краят на цветовата декорация е дефиниран само кодът трябва да бъде споменат а номерът на цветът не.
                Ако го споменете той просто ще се смени на този цвят на който сте задали а няма да спре. Можете да оцветявате и с литерали
                (отваряте миднайт командер давате F9 избирате litheral натискате ESC и записвате кода на цвета).

                По някога бихте искали да проверите дали даден потребител има някакъв флаг в бота и дали той може да извърш нещо например да
                е поне мастер. Това може да бъде направено с командата [matchattr]. Синтаксисът е [matchattr <handle> <flag(s)> [channel]].

                <handle> е името на потребителя който искате да проверите, това трябва да бъде псевдонима с който потребителя е аднат в бота
                а не текуштият псевдоним на потребителя.

                <flag(s)> са флаговете които искате да проверите. Това може да бъде поредица от флагове или само един. Забележете че ако използвате
                'of' за <flag(s)> ботът ще провери потребителят има +o ИЛИ +f, а не +o И +f. Моцете да разделите различните фалгове с | или &
                ако искате да проверите дали потребителят има само един от тях или всичките например "o&f" ще накара бота да провери дали
                потребителя има +o и +f.

                [channel] е каналът за който проверявате дали има флагове. Забележете че ако зададете канал се проверяват само флаговете на
                потребителя за канала, а не глобалните флагове. Например [matchattr $hand o|o $chan] ще провери дали потребителя има глобални
                операторски права или такива за $chan, [matchattr $hand o&m $chan] ще провери дали потребителят има глобални операторски права
                и дали е мастер за $chan.

                Много полезна команда е [catch]. С тази команда можете да изпълнявате нещо и да 'хванете' грешката ако има такава и да
                предотвратите провала на целият ви скрипт. Под някой обстоятелстава ще е много по лесно да 'хванете' грешката отколкото
                да ви излязат милиони грешки. Синтаксисът е [catch <command>].

                <command> е това което изкате да изпълните заедно с параметрите. Просто го направете така както го бихте изпълнили нормално
                без да използвате командата catch.

                [catch] командата ще върне 0 ако няма грешки или положително число.

                Например ако unbind dcc командата die, е по добре да го направите така [catch { unbind dcc n die *dcc:server:die }], защото
                ако ботът не е свързан към IRC трябва да използвате [catch { unbind dcc n die *dcc:die }]. По този начин много лесно можете
                да unbind командата die без никакви проблеми, защото ако unbind команда която не съществува ботът ви ще даде грешка и ще падне.

                Сега ще продължим с няколко основни команди които можете да пратите към сървърът. IRC командите са горе-долу лесни и се пращат
                направо към сървърът със server output командите.

                Това вече беше казано но ще го повторим. За да пратите съобщение командата към сървърът е [PRIVMSG]. Синтаксистт е
                [PRIVMSG <nickname/channel> :<message>].

                <nickname/channel> е псевдонимът или каналът към който искате да пратите съобшениято.

                <message> е съобщението което искате да бъде пратено. Забележете че двете : пред съобщението са задължителни.

                Можете да пратите notice по съвсем същият начин просто трябва да смените "PRIVMSG" с "NOTICE".

                Можете да пратите CTCP като декорирате кода малко в началото на вашето съобщение. Кодът за CTCP е \001 последван от типа
                CTCP който искате да пратите, след това можете да сложите параметри които искате да бъдат пратени. Например ако искате да
                пратите CTCP PING към някой синтаксисът е [putserv "PRIVMSG <nickname/channel> :\001PING $nick"].

                Забележете че много клиенти не поддържат CTCP-а с малки букви така че се обедете че го пишете с главни букви.

                Има един CTCP който всъщност не е CTCP, но се праща по същият начин по който се праща CTCP. Това е 'ACTION' типа.
                'ACTION' типа прави същото което прави командата /me в mIRC или BitchX. Например ако исакте да напишете
                "/me feels tired of lecturing" синтаксисът ще е [putserv "PRIVMSG <nickname/channel> :\001ACTION feels tired of lecturing"].

                Ако искате да следите за /me в канал трябва да използвате bind командата по следният начин: bind ctcp - ACTION proc_me

                За да invite някой просто изпратете следното до IRC сървърът "INVITE <nickname> <channel>".

                <nickname> е псевдонимът който искате да invite.

                <channel> е каналът в който искате да invite човека.

                За да вкарате бота в канал ръчно тряба да пратите "JOIN <channel> [key]" към сървърът.

                <channel> е каналът в който искате бота да влезе.

                [key] е ключът който ботът трябва да използва за да влезе в канала.

                Забележете че ако използвате тази команда каналът няма да бъде добавен към списъкът с канали на Eggdrop-а и той веднага ще
                излезе от него защото не го разпознава като валиден, това може да бъде направено с командата [channel add]. Можете да намерите
                повече за това в tcl-commands.doc.

                За да накарате бота ръчно да излезе от канал използвайте "PART <channel> :[message]".

                <channel> е името на канала от който искате бота да излезе.

                [message] е съобщението което искате бота да прати при излизане (UniBG няма подобни съобщения).

                Забележете че след излизането бота ще влезе отново в канала защото канала е в списъкъ с активните канали на бота. Ако искате
                да го изкарате перманентно използвайте [channel remove]. Можете да намерите повече за това също в tcl-commands.doc.

                Някои неща са взаимствани от TCL Guide от Marijn van Zon ([email protected]) за което благодарим.
The quieter you become, the more you are able to hear! :AR! https://www.FreeUniBG.eu :YMDEVIL:
Публикувай отговор

Кой е на линия

Потребители разглеждащи този форум: 0 регистрирани и 4 госта