Compare commits
11 Commits
a3295272f0
...
master
Author | SHA1 | Date | |
---|---|---|---|
2d0a8e13a6 | |||
67547b7226 | |||
fabc2bcf86 | |||
2e287bb2d8 | |||
4dc534848b | |||
33b5a19aae | |||
ea7a690234 | |||
87e345bbfb | |||
37210743bc | |||
a357bbd1f8 | |||
cc4f2584ed |
5
Makefile
5
Makefile
@ -25,4 +25,7 @@ mrproper: clean
|
|||||||
|
|
||||||
install: bin/catwalk
|
install: bin/catwalk
|
||||||
@mkdir -p /usr/local/bin/
|
@mkdir -p /usr/local/bin/
|
||||||
cp bin/catwalk /usr/local/bin/
|
install -p bin/catwalk /usr/local/bin/
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -f /usr/local/bin/catwalk
|
33
README.md
33
README.md
@ -1,3 +1,32 @@
|
|||||||
# catwalk-cli
|
# Catwalk CLI
|
||||||
|
|
||||||
Interface en lignes de commande pour le jeu Catwalk
|
Interface en lignes de commande pour le jeu Catwalk
|
||||||
|
|
||||||
|
## Instructions d'installation
|
||||||
|
|
||||||
|
**Attention: La compilation et l'exécution de Catwalk CLI requièrent l'installation de la bibliothèque [libcatwalk](https://git.kaz.bzh/valentin/libcatwalk), version antérieure ou égale à [version 0.1 alpha](https://git.kaz.bzh/valentin/libcatwalk/releases/tag/v0.1alpha).**
|
||||||
|
|
||||||
|
1. Il faut d'abord cloner le dépôt et y accéder (faire attention à la version) :
|
||||||
|
```
|
||||||
|
$ git clone https://git.kaz.bzh/valentin/catwalk-cli.git -n -b v0.1alpha
|
||||||
|
$ cd catwalk-cli
|
||||||
|
```
|
||||||
|
2. Ensuite, il faut compiler :
|
||||||
|
```
|
||||||
|
$ make
|
||||||
|
```
|
||||||
|
3. Enfin, il faut installer :
|
||||||
|
```
|
||||||
|
$ sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Utilisation
|
||||||
|
|
||||||
|
Une aide précise est disponible sur le [wiki](https://git.kaz.bzh/valentin/catwalk-cli/wiki/).
|
||||||
|
|
||||||
|
## Désinstallation
|
||||||
|
|
||||||
|
Pour désinstaller, il faut exécuter
|
||||||
|
```
|
||||||
|
$ sudo make uninstall
|
||||||
|
```
|
145
src/interact.c
145
src/interact.c
@ -102,71 +102,128 @@ int read_from_stdin(char *str, int length)
|
|||||||
|
|
||||||
void interact(int width)
|
void interact(int width)
|
||||||
{
|
{
|
||||||
|
/* Avant de permettre à l'utilisateur d'intéragir
|
||||||
|
* avec la grille, encore faut-il la générer ! */
|
||||||
grid *gd = init_grid(width);
|
grid *gd = init_grid(width);
|
||||||
|
|
||||||
printf("Welcome to Catwalk CLI. Type 'help' or '?' to see all available commands.\n");
|
|
||||||
char prompt[COMMAND_MAX_SIZE] = "";
|
|
||||||
char buffer[COMMAND_MAX_SIZE] = "";
|
|
||||||
|
|
||||||
refresh_grid(gd);
|
refresh_grid(gd);
|
||||||
init_player_route(gd);
|
init_player_route(gd);
|
||||||
|
|
||||||
|
// Afficher un message de bienvenue et d'aide courte
|
||||||
|
printf("Welcome to Catwalk CLI. Type 'help' or '?' to see all available commands.\n");
|
||||||
|
|
||||||
|
/* Création des deux tableaux de caractères contenant les
|
||||||
|
* entrées de l'utilisateur. Le premier sert à stocker
|
||||||
|
* directement les entrées de l'utilisateur. Le second est
|
||||||
|
* utilisé pour permettre la copie et la modification
|
||||||
|
* du premier. */
|
||||||
|
char prompt[COMMAND_MAX_SIZE] = "";
|
||||||
|
char buffer[COMMAND_MAX_SIZE] = "";
|
||||||
|
|
||||||
|
// Boucle principale
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
|
// vérification de la non-vacuité de prompt
|
||||||
if (is_whitespace(prompt))
|
if (is_whitespace(prompt))
|
||||||
{
|
{
|
||||||
printf("catwalk> ");
|
printf("catwalk> "); // affichage
|
||||||
|
|
||||||
|
// on met dans "prompt" l'entrée de l'utilisateur
|
||||||
read_from_stdin(prompt, COMMAND_MAX_SIZE);
|
read_from_stdin(prompt, COMMAND_MAX_SIZE);
|
||||||
|
|
||||||
|
/* on met une copie de "prompt" dans
|
||||||
|
* "buffer" sans les espaces */
|
||||||
ltrim(buffer, prompt);
|
ltrim(buffer, prompt);
|
||||||
|
|
||||||
|
// on remet tout dans "prompt"
|
||||||
strcpy(prompt, buffer);
|
strcpy(prompt, buffer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* Succession d'expressions conditionnelles.
|
||||||
|
* Fonctionnement de l'entrée : l'utilisateur
|
||||||
|
* entre une suite de commandes; elles sont
|
||||||
|
* éxécutées successivement : par exemple,
|
||||||
|
* "llurus" est éxécuté comme cela :
|
||||||
|
* - "l" comme "left" (X2)
|
||||||
|
* - "u" comme "up"
|
||||||
|
* - "r" comme "right"
|
||||||
|
* - "u" comme "up"
|
||||||
|
* - "s" comme "show"
|
||||||
|
* Pour éviter les problèmes du type :
|
||||||
|
* prompt = "undo" : j'éxécute "u" pour "up"
|
||||||
|
* -> prompt = "ndo": commande inconnue,
|
||||||
|
* Les commandes en toutes lettres sont testées
|
||||||
|
* avant les commandes abrégées. */
|
||||||
if STR_STARTS_WITH(prompt, "help")
|
if STR_STARTS_WITH(prompt, "help")
|
||||||
{
|
{
|
||||||
print_help();
|
print_help(); // action correspondante
|
||||||
|
|
||||||
|
/* on enlève "help" de prompt et décale
|
||||||
|
* les caractères en conséquence */
|
||||||
strcpy(buffer, prompt+strlen("help"));
|
strcpy(buffer, prompt+strlen("help"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "?")
|
else if STR_STARTS_WITH(prompt, "?")
|
||||||
{
|
{
|
||||||
print_help();
|
print_help(); // action correspondante
|
||||||
|
|
||||||
|
/* on enlève "?" de prompt et décale
|
||||||
|
* les caractères en conséquence */
|
||||||
strcpy(buffer, prompt+strlen("?"));
|
strcpy(buffer, prompt+strlen("?"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "show")
|
else if STR_STARTS_WITH(prompt, "show")
|
||||||
{
|
{
|
||||||
|
/* on affiche la grille, en précisant qu'elle
|
||||||
|
* est interactive (afficher le chemin) */
|
||||||
print_interactive_grid(gd);
|
print_interactive_grid(gd);
|
||||||
|
|
||||||
|
/* on enlève "show" de prompt et décale
|
||||||
|
* les caractères en conséquence */
|
||||||
strcpy(buffer, prompt+strlen("show"));
|
strcpy(buffer, prompt+strlen("show"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "reset")
|
else if STR_STARTS_WITH(prompt, "reset")
|
||||||
{
|
{
|
||||||
|
// Réinitialisation de la grille
|
||||||
|
|
||||||
|
/* si le chemin du joueur ne
|
||||||
|
* contient qu'un élément */
|
||||||
if (gd->player_route->first->next == NULL)
|
if (gd->player_route->first->next == NULL)
|
||||||
{
|
{
|
||||||
|
// demander à jouer d'abord
|
||||||
printf("Play first!\n");
|
printf("Play first!\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* supprimer récursivement tous les éléments
|
||||||
|
* du chemin du joueur, sauf le premier */
|
||||||
delete_element(gd->player_route->first->next);
|
delete_element(gd->player_route->first->next);
|
||||||
gd->player_route->first->next = NULL;
|
gd->player_route->first->next = NULL;
|
||||||
gd->player_route->last = gd->player_route->first;
|
gd->player_route->last = gd->player_route->first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// supprimer "reset" de prompt
|
||||||
strcpy(buffer, prompt+strlen("reset"));
|
strcpy(buffer, prompt+strlen("reset"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "route")
|
else if STR_STARTS_WITH(prompt, "route")
|
||||||
{
|
{
|
||||||
|
// afficher le chemin
|
||||||
print_route(gd->player_route);
|
print_route(gd->player_route);
|
||||||
strcpy(buffer, prompt+strlen("route"));
|
|
||||||
|
// supprimer "route" de prompt
|
||||||
|
strcpy(buffer, prompt+strlen("route"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if (STR_STARTS_WITH(prompt, "exit") || STR_STARTS_WITH(prompt, "quit") || STR_STARTS_WITH(prompt, "q"))
|
else if (STR_STARTS_WITH(prompt, "exit") || STR_STARTS_WITH(prompt, "quit") || STR_STARTS_WITH(prompt, "q"))
|
||||||
{
|
{
|
||||||
|
// arrêter l'interaction
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "undo")
|
else if STR_STARTS_WITH(prompt, "undo")
|
||||||
{
|
{
|
||||||
|
// annulation imposible s'il n'y a qu'un unique élément
|
||||||
if (gd->player_route->first->next == NULL)
|
if (gd->player_route->first->next == NULL)
|
||||||
{
|
{
|
||||||
printf("Can't undo! (single element)\n");
|
printf("Can't undo! (single element)\n");
|
||||||
@ -175,87 +232,130 @@ void interact(int width)
|
|||||||
{
|
{
|
||||||
pop_back(gd->player_route);
|
pop_back(gd->player_route);
|
||||||
}
|
}
|
||||||
strcpy(buffer, prompt+strlen("z"));
|
|
||||||
|
// supprimer "undo" de prompt
|
||||||
|
strcpy(buffer, prompt+strlen("undo"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "left")
|
else if STR_STARTS_WITH(prompt, "left")
|
||||||
{
|
{
|
||||||
|
/* tenter de se déplacer, et si erreur,
|
||||||
|
* afficher le message correspondant */
|
||||||
switch (move_left(gd->player_route))
|
switch (move_left(gd->player_route))
|
||||||
{
|
{
|
||||||
case 1: puts("Cannot move: border of the grid"); break;
|
case 1: puts("Cannot move: border of the grid"); break;
|
||||||
case 2: puts("Cannot move: already went there"); break;
|
case 2: puts("Cannot move: already went there"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// supprimer "left" de prompt
|
||||||
strcpy(buffer, prompt+strlen("left"));
|
strcpy(buffer, prompt+strlen("left"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "right")
|
else if STR_STARTS_WITH(prompt, "right")
|
||||||
{
|
{
|
||||||
|
/* tenter de se déplacer, et si erreur,
|
||||||
|
* afficher le message correspondant */
|
||||||
switch (move_right(gd->player_route))
|
switch (move_right(gd->player_route))
|
||||||
{
|
{
|
||||||
case 1: puts("Cannot move: border of the grid"); break;
|
case 1: puts("Cannot move: border of the grid"); break;
|
||||||
case 2: puts("Cannot move: already went there"); break;
|
case 2: puts("Cannot move: already went there"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// supprimer "right" de prompt
|
||||||
strcpy(buffer, prompt+strlen("right"));
|
strcpy(buffer, prompt+strlen("right"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "up")
|
else if STR_STARTS_WITH(prompt, "up")
|
||||||
{
|
{
|
||||||
|
/* tenter de se déplacer, et si erreur,
|
||||||
|
* afficher le message correspondant */
|
||||||
switch (move_up(gd->player_route))
|
switch (move_up(gd->player_route))
|
||||||
{
|
{
|
||||||
case 1: puts("Cannot move: border of the grid"); break;
|
case 1: puts("Cannot move: border of the grid"); break;
|
||||||
case 2: puts("Cannot move: already went there"); break;
|
case 2: puts("Cannot move: already went there"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// supprimer "up" de prompt
|
||||||
strcpy(buffer, prompt+strlen("up"));
|
strcpy(buffer, prompt+strlen("up"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "down")
|
else if STR_STARTS_WITH(prompt, "down")
|
||||||
{
|
{
|
||||||
|
/* tenter de se déplacer, et si erreur,
|
||||||
|
* afficher le message correspondant */
|
||||||
switch (move_down(gd->player_route))
|
switch (move_down(gd->player_route))
|
||||||
{
|
{
|
||||||
case 1: puts("Cannot move: border of the grid"); break;
|
case 1: puts("Cannot move: border of the grid"); break;
|
||||||
case 2: puts("Cannot move: already went there"); break;
|
case 2: puts("Cannot move: already went there"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// supprimer "down" de prompt
|
||||||
strcpy(buffer, prompt+strlen("down"));
|
strcpy(buffer, prompt+strlen("down"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "s")
|
else if STR_STARTS_WITH(prompt, "s")
|
||||||
{
|
{
|
||||||
|
// afficher la grille
|
||||||
print_interactive_grid(gd);
|
print_interactive_grid(gd);
|
||||||
|
|
||||||
|
// supprimer "s" de prompt
|
||||||
strcpy(buffer, prompt+strlen("s"));
|
strcpy(buffer, prompt+strlen("s"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "l")
|
else if STR_STARTS_WITH(prompt, "l")
|
||||||
{
|
{
|
||||||
|
// se déplacer
|
||||||
switch (move_left(gd->player_route))
|
switch (move_left(gd->player_route))
|
||||||
{
|
{
|
||||||
case 1: puts("Cannot move: border of the grid"); break;
|
case 1: puts("Cannot move: border of the grid"); break;
|
||||||
case 2: puts("Cannot move: already went there"); break;
|
case 2: puts("Cannot move: already went there"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MàJ de prompt
|
||||||
strcpy(buffer, prompt+strlen("l"));
|
strcpy(buffer, prompt+strlen("l"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "r")
|
else if STR_STARTS_WITH(prompt, "r")
|
||||||
{
|
{
|
||||||
|
// se déplacer
|
||||||
switch (move_right(gd->player_route))
|
switch (move_right(gd->player_route))
|
||||||
{
|
{
|
||||||
case 1: puts("Cannot move: border of the grid"); break;
|
case 1: puts("Cannot move: border of the grid"); break;
|
||||||
case 2: puts("Cannot move: already went there"); break;
|
case 2: puts("Cannot move: already went there"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MàJ de prompt
|
||||||
strcpy(buffer, prompt+strlen("r"));
|
strcpy(buffer, prompt+strlen("r"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "u")
|
else if STR_STARTS_WITH(prompt, "u")
|
||||||
{
|
{
|
||||||
|
// se déplacer
|
||||||
switch (move_up(gd->player_route))
|
switch (move_up(gd->player_route))
|
||||||
{
|
{
|
||||||
case 1: puts("Cannot move: border of the grid"); break;
|
case 1: puts("Cannot move: border of the grid"); break;
|
||||||
case 2: puts("Cannot move: already went there"); break;
|
case 2: puts("Cannot move: already went there"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MàJ de prompt
|
||||||
strcpy(buffer, prompt+strlen("u"));
|
strcpy(buffer, prompt+strlen("u"));
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else if STR_STARTS_WITH(prompt, "d")
|
else if STR_STARTS_WITH(prompt, "d")
|
||||||
|
{
|
||||||
|
switch (move_down(gd->player_route))
|
||||||
|
{
|
||||||
|
case 1: puts("Cannot move: border of the grid"); break;
|
||||||
|
case 2: puts("Cannot move: already went there"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MàJ de prompt
|
||||||
|
strcpy(buffer, prompt+strlen("d"));
|
||||||
|
ltrim(prompt, buffer);
|
||||||
|
}
|
||||||
|
else if STR_STARTS_WITH(prompt, "z")
|
||||||
{
|
{
|
||||||
|
// annuler, mais seulement si possible
|
||||||
if (gd->player_route->first->next == NULL)
|
if (gd->player_route->first->next == NULL)
|
||||||
{
|
{
|
||||||
printf("Can't undo! (single element)\n");
|
printf("Can't undo! (single element)\n");
|
||||||
@ -264,30 +364,25 @@ void interact(int width)
|
|||||||
{
|
{
|
||||||
pop_back(gd->player_route);
|
pop_back(gd->player_route);
|
||||||
}
|
}
|
||||||
strcpy(buffer, prompt+strlen("undo"));
|
|
||||||
ltrim(prompt, buffer);
|
// MàJ de prompt
|
||||||
}
|
strcpy(buffer, prompt+strlen("z"));
|
||||||
else if STR_STARTS_WITH(prompt, "z")
|
|
||||||
{
|
|
||||||
switch (move_down(gd->player_route))
|
|
||||||
{
|
|
||||||
case 1: puts("Cannot move: border of the grid"); break;
|
|
||||||
case 2: puts("Cannot move: already went there"); break;
|
|
||||||
}
|
|
||||||
strcpy(buffer, prompt+strlen("d"));
|
|
||||||
ltrim(prompt, buffer);
|
ltrim(prompt, buffer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// afficher un message d'erreur
|
||||||
printf("Unrecognized command : '%s'!\n", prompt);
|
printf("Unrecognized command : '%s'!\n", prompt);
|
||||||
prompt[0] = '\0';
|
prompt[0] = '\0'; // effacer prompt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (gd->player_route->last->x == gd->end[0] && gd->player_route->last->y == gd->end[1])
|
if (gd->player_route->last->x == gd->end[0] && gd->player_route->last->y == gd->end[1])
|
||||||
{
|
{
|
||||||
print_interactive_grid(gd);
|
print_interactive_grid(gd); // afficher à nouveau la grille
|
||||||
|
|
||||||
|
// afficher un message de fin
|
||||||
if (verify(gd))
|
if (verify(gd))
|
||||||
{
|
{
|
||||||
printf("You won!\n");
|
printf("You won!\n");
|
||||||
@ -297,11 +392,13 @@ void interact(int width)
|
|||||||
printf("You lost!\n");
|
printf("You lost!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// régénérer la grille
|
||||||
random_start(gd);
|
random_start(gd);
|
||||||
refresh_grid(gd);
|
refresh_grid(gd);
|
||||||
reset_player_route(gd);
|
reset_player_route(gd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pour finir, détruire la grille
|
||||||
delete_grid(gd);
|
delete_grid(gd);
|
||||||
}
|
}
|
||||||
|
11
src/main.c
11
src/main.c
@ -24,7 +24,7 @@
|
|||||||
#include "interact.h"
|
#include "interact.h"
|
||||||
#include "simplegen.h"
|
#include "simplegen.h"
|
||||||
|
|
||||||
#define PROGRAM_VERSION "1.0"
|
#define PROGRAM_VERSION "Alpha 0.1"
|
||||||
|
|
||||||
void help(char *program_name)
|
void help(char *program_name)
|
||||||
{
|
{
|
||||||
@ -38,12 +38,17 @@ Usage : %s [parameters]\n",
|
|||||||
-s, --simple Create a grid, without permitting to play.\n\
|
-s, --simple Create a grid, without permitting to play.\n\
|
||||||
-w, --width <width> Create a grid with the given width.\n\
|
-w, --width <width> Create a grid with the given width.\n\
|
||||||
--interactive, --simple, --help and --version are mutually exclusive: the last argument is kept.\n\n\
|
--interactive, --simple, --help and --version are mutually exclusive: the last argument is kept.\n\n\
|
||||||
This program was made with love by Valentin Moguerou <valentin@moguerou.net>.");
|
This program was made with love by Valentin Moguerou <valentin@kaz.bzh>.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void version()
|
void version()
|
||||||
{
|
{
|
||||||
printf("Catwalk CLI version 1.0\n");
|
puts("Catwalk CLI version alpha 0.1\n\
|
||||||
|
Copyright (C) 2021 Valentin Moguerou <valentin@kaz.bzh>\n\
|
||||||
|
License GPLv3+ : GNU GPL version 3 or later\n\
|
||||||
|
<https://gnu.org/licenses/gpl.html>\n\
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY.\n\
|
||||||
|
This is free software, and you are welcome to redistribute it under certain conditions.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
void simple_generation(int width)
|
void simple_generation(int width)
|
||||||
{
|
{
|
||||||
grid *gd = init_grid(width);
|
grid *gd = init_grid(width);
|
||||||
|
random_start(gd);
|
||||||
refresh_grid(gd);
|
refresh_grid(gd);
|
||||||
|
|
||||||
print_simple_grid(gd);
|
print_simple_grid(gd);
|
||||||
|
Reference in New Issue
Block a user