Как да си направим TCL !

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
версията им на .

Сега ще обясним двете основни команди в 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 стойности които сървърът ви връща можете да видите на
можете да ползвате и следния 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 сякаш е използвана командата [list] за тази цел. Ще научите повече за [list] командата, но вече трябва да знаете за разликата между "args" и всяко друго име.
Например, ако извикате процедурата [proc test { nick channel args } { <body> }] с
[test $nick $channel $handle $host], ще сложи $nick в $nick, $channel в $channel, а $handle and $host в $args, но ние ви разубеждавам да използвате командата "args" като параметър, поне докато научите какво е
прави командата [list].

<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]].
Ето няколко бързи и лесни примера които обясняват командата:

Ето няколко примера:

# Добавя 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, и ботът да е оператор)


Автор
LuXiRiS

ИЗТОЧНИК http://web-tourist.net