06.09.2014, 21:56
(
Последний раз редактировалось TheChaoz; 07.09.2014 в 16:29.
Причина: Removed extra tags
)
YSI Series - Y_INI
Introducciуn
Bueno, dado que mucha gente me ha preguntado sobre el uso de algunos includes pertenecientes a la librerнa YSI, he decidido comenzar una serie de tutoriales al respecto.
El primero sera este en el cual intentare explicar como utilizar Y_INI correctamente y de una forma simple. Claro esta que si quieren alguna librerнa en particular, pueden decirme e intentare realizar dicho tutorial si asн lo creo conveniente y/o posible.
Les recuerdo como siempre que si ven algun error me avisen para poder corregirlo.
Nota: Si bien es un tutorial sobre Y_INI, no me concentrare concretamente en que hace cada funciуn del mismo, si no, mas bien en como utilizarlas de una forma practica con ejemplos.
Indice
- Introducciуn
- Indice
- Introducciуn a INI
- їQuй es INI?
- Secciones, entradas y comentarios
- Secciones
- Entradas
- Comentarios
- Secciones
- їQuй es INI?
- Y_INI Bбsico
- Creando un archivo
- Escritura
- Lectura
- Forma basica
- Con argumentos extra
- Forma basica
- Creando un archivo
- Y_INI Simplificado
- Lectura
- Lectura
- Y_INI ParseFile
- fname
- remoteFormat
- bFileFirst
- bExtra y extra
- bLocal
- bPassTag
- bFilter & filter
- fname
- Final
Introducciуn a INI
Si queremos poder utilizar todas las caracterнsticas de Y_INI, primero debemos conocer mejor el formato INI.
їQuй es INI?
El formato INI es un formato (valida la redundancia) utilizado para almacenar mas ordenadamente datos. Estos datos tienen la caracterнstica particular de que poseen una descripciуn similar.
Ejemplo:
Si quisiйramos formar una base de datos sobre personas de nuestra empresa tendrнamos datos personales como por ejemplo su nombre, apellido, direcciуn, edad, nacionalidad y datos laborales como por ejemplo la fecha en la que ingreso a trabajar, su sueldo y el puesto que ocupa. Por lo cual para formar nuestra base de datos necesitarнamos almacenar los mismos, por lo que nuestros archivos INI podrнan ser asн:
Код:
[Personales] Nombre=Nicolas Apellido=Rodriguez Edad=25 Direccion=Av. Espora 672 Nacionalidad=Argentina [Laborales] FechaIngreso=27/7/1998 Sueldo=18600 Cargo=Director Finanzas
Secciones y entradas
Secciones
Se llaman secciones a las divisiones creadas por los tags. Los tags se encuentran definidos por palabras encerradas entre corchetes ('[' ']'); estas secciones como se ve en el ejemplo anterior se utilizan para la mejor organizaciуn del documento.
Pero si se utilizan lectores relativamente avanzados, tambiйn brinda una mayor permanecer de lectura ya que si necesitamos un dato en particular buscaremos dentro de la secciуn del mismo y no por todo el documento en si.
Entradas
Las entradas estбn representadas por el conjunto de pares y valores que componen cada entrada.
Las entradas estбn compuertas por una llave o descripciуn (key) seguido de un '=' seguido de un valor (value).
Ejemplo:
[code]key=value[/key]
Una particularidad de las entradas es que no pueden repetirse iguales llaves a diferentes valores dentro de una misma secciуn, pues solo se leerб 1 de ellas (dependiendo del mйtodo de lectura sera la primera o ultima).
Ejemplo:
Код:
[Seccion1] key1=valor1 key2=valor2 key3=valor3 key1=valor54 [Seccion2] key1=valor1 key2=valor2 key3=valor3
Nota: Notemos que como los textos en formato INI se guardan en texto plano en el ejemplo anterior valorN (siendo N un numero) podrнa ser tanto un valor numйrico como el texto en si mismo; el tipo del valor dependerб de como se lo lea.
Comentarios
En este formato tambiйn podemos realizar comentarios, los cuales se indican colocando un ';' al comienzo del mismo.
Ejemplo:
Код:
key=value ;Esto es un comentario y no forma parte de la entrada
Y_INI Bбsico
Creando un archivo
Para poder trabajar con archivos INI primero necesitamos el archivo en si, por lo que debemos crearlo. Esto se realiza mediante una simple funciуn llamada INI_Open.
Ejemplo:
pawn Код:
new INI:file = INI_Open("ruta/de/nuestro/archivo.ini");
Ejemplo:
pawn Код:
INI_Open(file);
Escritura
Ahora que sabemos como crear nuestro archivo podemos escribir datos en el mismo. Esta podrнa considerarse la parte simple.
Ejemplo:
pawn Код:
new
INI:file = INI_Open("/Usuarios/TheChaoz.ini");
//Guardamos datos personales del usuario
//Seteamos el tag
INI_SetTag(file, "account_data");
//Guardamos datos
INI_WriteString(file, "Password", "12345");
INI_WriteInt(file, "Banned", 0);
//Guardamos informaciуn sobre las estadнsticas del usuario
INI_SetTag(file, "account_stats");
INI_WriteInt(file, "Score", 150);
INI_WriteInt(file, "Kills", 1500);
INI_WriteInt(file, "Deaths", 1500);
INI_WriteInt(file, "Money", 10000);
INI_WriteFloat(file, "SpawnX", 100.0);
INI_WriteFloat(file, "SpawnY", 100.0);
INI_WriteFloat(file, "SpawnZ", 1.0);
INI_Close(file);
Код:
[account_stats] SpawnZ = 1.000000 SpawnY = 100.000000 SpawnX = 100.000000 Money = 10000 Deaths = 1500 Kills = 1500 Score = 150 [account_data] Banned = 0 Password = 12345
Lectura
Y_INI brinda una gran variedad de formas de leer archivos, generalmente aquн es donde muchos usuarios no entienden como funciona el sistema y lo abandonan.
Intentare cubrir algunas de ellas con los aspectos mas bбsicos y simples.
Para leer un archivo utilizaremos la funciуn "INI_Load". Esta funciуn tiene algunos parбmetros opcionales los cuales iremos analizando uno por uno.
pawn Код:
INI_Load(filename[], bool:bExtra = false, extra = 0, bool:bLocal = true);
- filename[] - Es el nombre del archivo que abriremos (con la ruta claro esta).
- bExtra - Indicamos si enviaremos o no un parбmetro extra.
- extra - Es el parбmetro extra que podemos enviar
- bLocal - Indicamos si se carga el archivo solo en el script actual o en todos.
Forma bбsica
Esta forma se suele utilizar con archivos cuyos nombres ya conocemos de ante-mano, por ejemplo archivos de configuraciуn, datos del servidor (no de usuarios), etc.
Ejemplo:
Код:
;este es un archivo utilizado como ejemplo para el siguiente cуdigo [general] MustLogin=1 MustRegister=0 [version] Name=XXX Server Version=1.4 [other] DisableChat=0
pawn Код:
new
gLogin,
gRegister,
gName[24],
Float:gVersion,
gChat;
public OnFilterScriptInit()
{
INI_Load("/Config.ini");//Cargamos nuestro archivo
printf("[general] MustLogin: %i || MustRegister: %i", gLogin, gRegister);
printf("[versiуn] Name: %s || Version: %.1f", gName, gVersion);
printf("[other] DisableChat: %i", gChat);
return 1;
}
/*Aqui es donde hay algo de 'magia' que explicaremos mas adelante, pero por el momento lo que necesitamos saber es que luego de utilizar INI_Load, pawn leerб nuestro archivo
y linea por linea llamara a las siguientes callbacks segъn corresponda, indicando en 'name' el key y en value el valor de cada entrada.*/
//Fuera de cualquier callback y/o funciуn
//Este callback sera llamado ъnicamente con las entradas que estйn dentro del tag 'general'
INI:Config[general](name[], value[])
{
//Aqui leeremos las entradas del tag 'general'
INI_Int("MustLogin", gLogin);
INI_Int("MustRegister", gRegister);
return 0;//Este return solo es necesario pues utilizamos las macros provistas por Y_INI las cuales tienen en su definiciуn un return.
}
INI:Config[version](name[], value[])
{
//Aquн leeremos las entradas del tag 'versiуn'
INI_String("Name", gName, 24);
INI_Float("Version", gVersion);
return 0;
}
INI:Config[other](name[], value[])
{
//Aqui leeremos las entradas del tag 'other'
INI_Int("DisableChat", gChat);
return 0;
}
Код:
[general] MustLogin: 1 || MustRegister: 0 [version] Name: XXX Server || Version: 1.3 [other] DisableChat: 0
їPorque utilice variables globales?
Esto se debe a que utilice las macros que nos brinda Y_INI (INI_Int, INI_Float, INI_String). Estas macros incluyen un return dentro, es decir que si el valor es leнdo, ya no se ejecutara cуdigo luego de esa
linea. Esto no quiere decir que estemos obligados a utilizar este mйtodo siempre (aun que a veces puede ser ъtil).
Ejemplo:
pawn Код:
//Las siguientes lineas de cуdigo son anбlogas, solo que la primera no ejecutara cуdigo posterior al leer un dato y la segunda si:
INI_Float("Version", version);
if(!strcmp(name, "Version))
version = floatstr(value);
Con argumentos extra
Lo que esta forma nos permite es pasar un argumento extra al callback de carga (solo puede ser una variable y no un array).
Ejemplo:
Код:
;este es un archivo utilizado como ejemplo para el siguiente cуdigo [general] key1=132 key2=251 key3=512 key4=560 key5=2312 key6=1231
pawn Код:
new
gValues[10];
public OnFilterScriptInit()
{
INI_Load("/Numbers.ini", .bExtra=true, .extra=3);//Cargamos nuestro archivo indicando que recibirб un argumento extra y que dicho argumento es el numero 3 (este argumento podrнa ser variable)
for(new i; i<6; i++)
printf("key%i: %i", i+1, gValues[i]);
return 1;
}
//Aquн como podemos observar sera nuestro primer parбmetro el que reciba nuestro parбmetro extra.
INI:Numbers[general](number, name[], value[])
{
new
key[5];
//Lo que este cуdigo realiza es comparar uno por uno los nombres de cada entrada (comprobar sean key1-key6) y multiplicar el valor de dicha entrada por el parбmetro extra
for(new i; i<6; i++){
format(key, 5, "key%i", i+1);
if(!strcmp(name, key)) {
gValues[i] = strval(value)*number;
return 1;
}
}
return 0;
}
Код:
key1: 396 key2: 753 key3: 1536 key4: 1680 key5: 6936 key6: 3693
Y_INI Simplificado
Lectura
Al utilizar Y_INI tenemos muchas formas de leer archivos. El siguiente ejemplo es a mi parecer la forma mas simple de leer un archivo, pero tiene como desventaja la dependencia de otra librerнa (y_inline).
Ejemplo: (El siguiente ejemplo supone la correcta definiciуn de pData, array en la cual se almacenan los datos del jugador)
pawn Код:
stock LoginPlayer(playerid)
{
new
file[15 + MAX_PLAYER_NAME],
pName[MAX_PLAYER_NAME],
Float:P[3];
GetPlayerName(playerid, pName, MAX_PLAYER_NAME);
//Este es el callback inline, el cual es llamado 1 vez por cada entrada del archivo (los tags no estбn incluidos en este ejemplo)
inline Load(name[], value[])
{
//Notemos que las siguientes macros solo funcionan si se definieron los argumentos de nuestra funciуn con los nombres "name[]" y "value[]"
INI_Float("SpawnX", P[0]);
INI_Float("SpawnY", P[1]);
INI_Float("SpawnZ", P[2]);
INI_Int("Deaths", pData[playerid][Deaths]);
INI_Int("Kills", pData[playerid][Kills]);
if(!strcmp(name, "Money"))//Podrнamos usar la macro INI_Int, pero deberнamos crear una variable extra, ademas asi se ejemplifica otra forma de leer los datos
GivePlayerMoney(playerid, strval(value));
else if(!strcmp(name, "Score"))
SetPlayerScore(playerid, strval(value));
else if(!strcmp(name, "Banned") && strval(value))
Kick(playerid);
}
format(file, sizeof(file), "/Usuarios/%s.ini", pName);
INI_ParseFile(file, using inline "Load");//Realizamos la lectura del archivo indicando que la funciуn es inline (y se llama "Load") y esta en este bloque de codigo.
SetPlayerPos(playerid, P[0], P[1], P[2]);
return 1;//Al igual que antes, es necesario el return por utilizar las macros INI_{Float/Int/...}
}
Y_INI ParseFile
Esto en realidad no es avanzado, pero si no se entiende lo que se hace puede llegar a ser algo confuso, es por esto que mucha gente opta por no utilizar este include.
Comenzemos por analizar el header de la funciуn:
pawn Код:
stock bool:INI_ParseFile(fname[], remoteFormat[], bool:bFileFirst = false, bool:bExtra = false, extra = 0, bool:bLocal = true, bool:bPassTag = false, bool:bFilter = true, filter[] = "")
- fname
Representa el path del archivo que abriremos. Notemos que este path sigue siendo relativo desde la carpeta de nuestro servidor Scriptfiles como siempre.
Esta funciуn si el archivo puede ser abierto para lectura con йxito retornara 1, caso contrario 0.
- remoteFormat
Se podrнa decir que representa el nombre del callback. Pero es algo mas complicado que eso.
Aquн no solo indicaremos el nombre del callback, si no que tambiйn indicaremos como se cargara el archivo, o mejor dicho, que secciones.
Код:;Este es nuestro archivo ini a cargar llamado "test.ini" tagless_key = Texto ejemplo [tag1] tag1_key = 10 tag1_key2 = texto2 [tag2] tag2_key = texto3
pawn Код:main()
{
INI_ParseFile("test.ini", "testLoad");
}
forward testLoad(name[], value[]);
public testLoad(name[], value[])
{
printf("%s = \"%s\"", name, value);
}
Код:tagless_key = "Texto ejemplo" tag1_key = "10" tag1_key2 = "texto2" tag2_key = "texto3"
Pero que tal si solo quisiйramos cargar las entradas de un tag especifico. Tendrнamos que leer todo el archivo y encontrar los valores de nuestra entrada de alguna forma.
Bueno, aquн es donde Y_INI nos brinda una forma eficiente y cуmoda de hacer esto.
Ejemplo:
pawn Код:main()
{
INI_ParseFile("test.ini", "testLoad%s");
}
forward testLoad(name[], value[]);
public testLoad(name[], value[])
{
printf("%s = \"%s\"", name, value);
}
Код:tagless_key = "Texto ejemplo"
En nuestro ejemplo anterior se carga la secciуn sin tag, es decir que el %s del final, sera reemplazado por la cadena vacнa ("") y se llamara a la misma funciуn.
De la misma forma si quisiйramos cargar solo el tag "tag1" nuestro callback deberнa ser llamado "testLoadtag1".
Ejemplo:
pawn Код:main()
{
INI_ParseFile("test.ini", "testLoad%s");
}
forward testLoad(name[], value[]);
public testLoad(name[], value[])
{
printf("[sin tag] %s = \"%s\"", name, value);
}
forward testLoadtag1(name[], value[]);
public testLoadtag1(name[], value[])
{
printf("[tag1] %s = \"%s\"", name, value);
}
forward testLoadtag2(name[], value[]);
public testLoadtag2(name[], value[])
{
printf("[tag2] %s = \"%s\"", name, value);
}
Код:[sin tag] tagless_key = "Texto ejemplo" [tag1] tag1_key = "10" [tag1] tag1_key2 = "texto2" [tag2] tag2_key = "texto3"
Nota: Podemos utilizar el formato que queramos, no es necesario limitarnos a "NombreCallback%s" podrнamos utilizar algo asн tambiйn "NombreCallback_%s" y tambiйn funcionaria.
Importante: Si quisiйramos cargar solo un tag, podemos omitir crear los demбs callbacks y las entradas de los mismos no serбn procesadas.
Asн mismo, si quisiйramos insertar el nombre del archivo dentro del callback como lo hicimos con los tags, podrнamos hacerlo agregando un %s extra.
Ejemplo:
pawn Код:main()
{
INI_ParseFile("test.ini", "Load_%s_%s");
}
forward Load_tag1_test(name[], value[]);
public Load_tag1_test(name[], value[])
{
printf("[tag1] %s = \"%s\"", name, value);
}
Код:[tag1] tag1_key = "10" [tag1] tag1_key2 = "texto2"
- bFileFirst
Como vimos al final de la explicaciуn anterior, podнamos darle muchos formatos al callback que procesa las entradas para operar con la carga de los archivos.
Ya fuese solo un nombre estбtico y fijo (Sin ningъn especificado).
O con 1 especificado (solo 1 '%s'), en cuyo caso utilizarнamos tambiйn los tags del archivo (o bien el tag nulo "" en caso de que el archivo no tuviera tags).
O bien con 2 especificadores, en cuyo caso utilizarнamos tanto los tags del archivo como su nombre.
Ahora bien, este parбmetro nos permitirб utilizar solo el nombre del archivo sin necesidad de utilizar tambiйn el tag.
Ejemplo:
pawn Код:main()
{
INI_ParseFile("test.ini", "Load_%s", true);
}
forward Load_test(name[], value[]);
public Load_test(name[], value[])
{
printf("%s = \"%s\"", name, value);
}
Код:tagless_key = "Texto ejemplo" tag1_key = "10" tag1_key2 = "texto2" tag2_key = "texto3"
Importante: їCуmo se crea el callback si mi archivo tiene un espacio en el nombre y quiero pasarlo al callback? Los espacios dentro de los nombres de archivos serбn reemplazados por un '_'.
- bExtra y extra
Si bien son 2 parametros diferentes, se utilizan juntos SIEMPRE.
Estos argumentos son utilizados para pasar datos extra el callback, pues a veces no alcanza con enviar solo la entrada(key & value). Un caso sonde se ve mucho esto es en la carga de archivos de usuario, pues se necesita saber que usuario se esta cargando en ese momento.
Mientras que el parбmetro bExtra indicara si se pasara o no un argumento extra, el parбmetro extra sera quien reviva el valor de dicho argumento.
Nota: Solo podemos pasar 1 variable (no string). Si necesitamos pasar mas podemos utilizar inline o variables globales.
Ejemplo:
pawn Код:forward LoadUser(playerid, name[], value[]);
public LoadUser(playerid, name[], value[])
{
if(IsPlayerConnected(playerid)) {
new
pName[MAX_PLAYER_NAME];
GetPlayerName(playerid, pName, MAX_PLAYER_NAME);
printf("Lading user %s(%i): %s = \"%s\"", pName, playerid, name, value);
}
}
LoadPlayer(playerid)
{
INI_ParseFile("Users\\player.ini", "LoadUser", .bExtra = true, .extra = playerid);//Utilizamos el . antes del nombre de los parбmetros pues estos no estбn en orden.
}
- bLocal
Como vimos hasta ahora, en Y_INI (excepto que se utilice Y_INLINE) los archivos son cargados mediante callbacks, las cuales se definen con un public y un forward. Esto se debe a que al momento de llamarlas se utiliza
(hasta YSI 3.1) CallRemoteFunction, es decir que el callback debe estar dentro del MISMO script que la llamada realizada.
Con este parбmetro, si lo seteamos en true lo que haremos sera eliminar esta restricciуn, pues se realizara el llamado mediante CallRemoteFunction, permitiйndonos de esta forma que el callback este en otro script.
- bPassTag
Ya vimos como armar el callback definido en remoteFormat de muchas formas diferentes segъn nuestras necesidades.
La forma bбsica:
pawn Код:forward Nombre(name[], value[]);
public CallbackName(name[], value[])
{
//cуdigo
}
pawn Код:forward_tag Nombre(name[], value[]);
public CallbackName(name[], value[])
{
//cуdigo
}
pawn Код:forward Nombre(name[], value[]);
public CallbackName_tag_nombreArchivo(name[], value[])
{
//cуdigo
}
pawn Код:forward Nombre(name[], value[]);
public CallbackName_nombreArchivo(name[], value[])
{
//cуdigo
}
pawn Код:forward Nombre(name[], value[]);
public CallbackName_nombreArchivo_tag(name[], value[])
{
//cуdigo
}
pawn Код:forward Nombre(name[], value[]);
public CallbackName(extra, name[], value[])
{
//cуdigo
}
Esto lo que nos permite es recibir dentro del callback el tag como un parбmetro mas.
Ejemplo:
Код:;Este es nuestro archivo ini a cargar llamado "test.ini" tagless_key = Texto ejemplo [tag1] tag1_key = 10 tag1_key2 = texto2 [tag2] tag2_key = texto3
pawn Код:main()
{
INI_ParseFile("test.ini", "Load", .bPassTag = true);
}
forward Load(tag[], name[], value[]);
public Load(tag[], name[], value[])
{
printf("[%s] %s = \"%s\"", tag, name, value);
}
Код:[] tagless_key = "Texto ejemplo" [tag1] tag1_key = "10" [tag1] tag1_key2 = "texto2" [tag2] tag2_key = "texto3"
Ejemplo:
pawn Код:main()
{
INI_ParseFile("test.ini", "Load", .bExtra=true, .extra=100, .bPassTag = true);
}
forward Load(extra, tag[], name[], value[]);
public Load(extra, tag[], name[], value[])
{
printf("[%s] %s = \"%s\" || %i", tag, name, value, extra);
}
Nota: Este parбmetro no es excluyente con la utilizaciуn del formato %s para pasar el tag al nombre del callback, pero realmente no veo motivos para hacer esto.
- bFilter & filter
Estos parбmetros nos permiten cargar una serie de tags determinada.
Pero para entender mejor su correcto uso volverй primero sobre la estructura de los archivos INI.
Si bien esto no es un estбndar, no rompe con ninguno de ellos por lo tanto es completamente valido.
Dividiremos los nombres de los tags en 2 partes, una parte que llamaremos filtrable, y la otra sera el nombre.
De esta forma construiremos los tags (no es obligatorio a menos que se quieran utilizar filtros) de la siguiente forma:
Код:[@@Filtrable-nombre]
Ejemplo:
Код:;Este es nuestro archivo ini a cargar llamado "test.ini" tagless_key = Texto ejemplo [@@TEST-tag1] tag1_key = 10 tag1_key2 = texto2 [@@TEST-tag2] tag2_key = texto3 [@@TEST2-tag1] tag1_key = 1001 tag1_key2 = texto254 [@@TEST2-tag2] tag2_key = texto3645
pawn Код:main()
{
INI_ParseFile("test.ini", "Load", .bPassTag=true, .bFilter=true, .filter="TEST");
}
forward Load(tag[], name[], value[]);
public Load(tag[], name[], value[])
{
printf("[%s] %s = \"%s\"", tag, name, value);
}
Код:[] tagless_key = "Texto ejemplo" [tag1] tag1_key = "10" [tag1] tag1_key2 = "texto2" [tag2] tag2_key = "texto3"
Final
Espero que les haya servido y si ven algъn error por favor avнsenme asi lo corrijo.