[Inform 6] Ecriture d'un fichier texte

Pour discuter des langages que nous utilisons pour réaliser nos jeux : problèmes, solutions, suggestions...

Modérateurs: Stormi, Otto Grimwald

[Inform 6] Ecriture d'un fichier texte

Messagepar Yoruk le Lun Fév 05, 2018 7:50 am

Salut à tous,

Je fais appel aujourd'hui aux pros d'Inform 6, car là j'ai un souci...

J'aimerai écrire et lire un simple fichier texte. Les commandes qui vont bien sont @save pour écrire et @read.

Le DM4 précise :

The Z-machine can also load and save “auxiliary files” to or from the host machine. These should have names adhering to the “8 + 3” convention, that is, one to eight alphanumeric characters optionally followed by a full stop and one to three further alphanumeric characters. Where no such extension is given, it is assumed to be .AUX. Designers are asked to avoid using the extensions .INF, .H, .SAV or .Z5 or similar, to prevent confusion. Note that auxiliary files from different games may be sharing a common directory on the host machine, so that a filename should be as distinctive as possible. The two opcodes are:

Code: Tout sélectionner
@save buffer length filename -> R


Saves the byte array buffer (of size length) to a file, whose (default) name is given in the filename (a string array). Afterwards, R holds true on success, false on failure.

Code: Tout sélectionner
@restore buffer length filename -> R


Loads in the byte array buffer (of size length) from a file, whose (default) name is given in the filename (a string array). Afterwards, R holds the number of bytes successfully read.


Et pour ces fameux "byte arrays" :


The third way to create an array gives some text as an initial value, occasionally useful because one popular use for arrays is as “strings of characters” or “text buffers”. For instance:


Code: Tout sélectionner
Array players_name --> "Frank Booth";


is equivalent to the directive:

Code: Tout sélectionner
Array players_name --> 'F' 'r' 'a' 'n' 'k' ' ' 'B' 'o' 'o' 't' 'h';


Literal text like "Frank Booth" is a constant, not an array, and you can no more alter its lettering than you could alter the digits of the number 124. The array players_name is quite different: its entries can be altered. But this means it cannot be treated as if it were a string constant, and in particular can't be printed out with print (string). See below for the right way to do this.


Alors je souhaiterai enregistrer le contenu de plusieurs variables, mais j'ai du mal à saisir le fonctionnement des "byte array buffer". Entre les erreurs de compilation, les crashs à l'exécution, voici le seul code que j'ai réussi à produire et qui arrive à écrire quelque chose :

Code: Tout sélectionner
Array players_name --> "Frank Booth";


[Main  length R test ;

   length = 16;

   @save players_name length "test.sav" -> R  ;

   print "write";
   
   if (R==true)
   {
   print " ok";
   }
   else print " error";
   
   
   print "^^";
   
   @restore test 4 "Þ.AUX" -> R  ;
   
   if (R==true)
   {
   print " read ok";
   }
   else print " read error";
   
];


Le résultat est un fichier au nom étrange ("Þ.AUX") de 16 octets (logique) qui contient une lettre sur deux de ma chaîne et le reste des caractères d'erreur (caractères non visibles ici) :

Code: Tout sélectionner
 F r a n k B o


Et ce fichier n'est pas lisible par la méthode @restore. A l'exécution j'ai bien read ok mais j'ai un write error.

J'ai regardé le code des fonctions lecture et sauvegarde des librairies I6, mais bien qu'elles contiennent un @save et @restore le tableau d'octet qu'elles prennent en paramètre n'est pas construit dans la méthode, et je n'ai pas trouvé comment il l'était.

Des idées ?

Merci !
Yoruk, SATOR AREPO TENET OPERA ROTAS
Avatar de l’utilisateur
Yoruk
Grand Ancien
 
Messages: 1065
Inscription: Lun Juin 11, 2007 9:50 am
Localisation: Chiddes, à 150 mètres du lavoir

Re: [Inform 6] Ecriture d'un fichier texte

Messagepar Natrium le Lun Fév 05, 2018 6:55 pm

Ce que je vais dire ne va vraisemblablement pas te convenir, mais bon, étant donné que je ne connais pas Inform 6…

J'imagine que la Z-machine est bien capable de manipuler des fichiers puisqu'on peut faire des transcriptions (entre autres), mais je pense que Glulx est plus flexible pour ça.

En tout cas, la bibliothèque standard d'I7 ne permet de manipuler des fichiers que si on compile pour Glulx, ce qui ne doit pas être sans raison.

Mais s'il est vraiment nécessaire pour toi de rester en Z-machine, j'imagine que ça doit quand même être faisable et je laisse la parole à des gens plus compétents en la matière.

(Si tu peux nous dire ton utilisation exacte, ça pourrait peut-être aider ?)
Avatar de l’utilisateur
Natrium
Grand Ancien
 
Messages: 1164
Inscription: Mar Oct 04, 2011 11:18 pm

Re: [Inform 6] Ecriture d'un fichier texte

Messagepar Mule hollandaise le Sam Fév 10, 2018 3:59 pm

Coucou, c'est tout à fait possible, mais ça n'est pas utilisé dans beaucoup de jeux ! (Ça s'appelle l' "Extended Save" je crois.)

En tout cas apparemment ça a marché pour la bibliothèque "achievements.h" de Vince Laviano, que je te mets en pièce jointe, au cas où... Mais il a fait des trucs un peu différents donc je ne sais pas si ça peut aider.
(Au lieu d'utiliser les byte arrays il a utilisé les buffer arrays, qui sont la même chose sauf la taille de la première case, de taille 2 (1 pour les byte arrays). Du coup y'a un moment il faut qu'il décale des trucs vers la gauche.)

J'ai essayé de bidouiller ton code, j'ai la sauvegarde qui marche mais pas le restore x) Voilà ce que j'ai trouvé :

  • Si tu veux donner une suggestion de nom à ta sauvegarde, il faut que le nom soit dans un byte array (et pas juste entre guillemets). C'est cette erreur. Je l'ai mis dans mon code.
  • Sache que ce nom de fichier n'est qu'une suggestion, et que certains interpréteurs (Gargoyle pour Linux par exemple) ouvrent systématiquement la fenêtre qui demande où sauvegarder, etc. C'est contraire à la spécification mais il n'empêche qu'ils le font....
  • J'ai rajouté le dernier argument optionnel mais il est lui aussi ignoré par les interpréteurs........ grmf
  • Tu avais oublié de déclarer ton tableau "test" qui contient le résultat du restore. Moi sur ton code j'ai un crash "attempted to write to illegal address 0x0", je pense que c'est à cause de ça. Mais je ne sais pas trop comment le déclarer, j'avoue ! C'est sans doute la ligne qui est à améliorer...
  • Si tu remplaces "test" par "players_name", tu obtiens un 'read error' (mais plus de crash). À voir si "players_name" a été changé ou non...

Si tu trouves, ça m'intéresse ! En tout cas on dirait qu'il faudrait une extension I6 pour faire les sauvegardes plus simplement (genre qui convertit tout en les bons types, etc.), ou en tout cas une extension qui convertit les tableaux de différents formats entre eux...

Code: Tout sélectionner
Array players_name --> "Frank Booth";
Array test -> 100; ! cette ligne est sans doute fausse : array test string 100? array test buffer 100?

Array filename --> "test.sav";


[Main  length_save length_restore R test prompt ;

   length_save = players_name-->0;

   @save players_name length_save filename prompt -> R  ;

   print "write";
   
   if (R==true)
   {
   print " ok";
   }
   else print " error";
   
   
   print "^^";
   
   length_restore = players_name-->0;
   @restore test length_restore filename prompt -> R  ;
   
   if (R==true)
   {
   print " read ok";
   }
   else print " read error";
   
];
Fichiers joints
achievements.h
(36.04 Kio) Téléchargé 113 fois
Mule hollandaise
Grand Ancien
 
Messages: 1123
Inscription: Mar Aoû 29, 2006 10:57 pm

Re: [Inform 6] Ecriture d'un fichier texte

Messagepar Yoruk le Sam Fév 10, 2018 5:44 pm

Hmmm.... Je me rends compte en voyant le message de Mule que ma réponse à ton message, Natrium à disparu...? Pour te répondre j'avais indiqué qu'effectivement en I6 c'est possible selon moi, vu que les interpréteurs permettent d'enregistrer des transcripts et des fichiers de sauvegarde. La fonction utilisée est bien @save, mais je n'arrivais pas à comprendre comment le fameux tableau de bytes était généré. Après si pour des questions de facilité je dois switcher en glulxe, c'est pas un souci non plus. :)

@Mule : Super merci je regarde ça et je vous tiens au courant.
Yoruk, SATOR AREPO TENET OPERA ROTAS
Avatar de l’utilisateur
Yoruk
Grand Ancien
 
Messages: 1065
Inscription: Lun Juin 11, 2007 9:50 am
Localisation: Chiddes, à 150 mètres du lavoir

Re: [Inform 6] Ecriture d'un fichier texte

Messagepar auraes le Sam Fév 24, 2018 7:56 pm

C'est fait ! (je savais pas que c'était possible.)
Code: Tout sélectionner
!% -Cu
!% -v8
!% -~S

Array nom string "nom_fichier";

Array data_save buffer "Test de Save and Restore";

Array data_restore buffer 256;
   
[ main   key flag n i;
   n = data_save-->0 + WORDSIZE;

   @save data_save n nom  -> flag;
   if (flag == 0) print "Save failed.^";

   @restore data_restore n nom  -> flag;
   if (flag == 0) print "Restore failed.^";

   i = 0;
   while (i < n) {
      print (char) data_restore->(WORDSIZE+i);
      i++;
   }

   new_line;
   .readkey;
   @read_char 1 ->key;
];

La réponse est là :
http://inform-fiction.org/zmachine/standards/z1point1/sect15.html#save
Avatar de l’utilisateur
auraes
Grand Ancien
 
Messages: 348
Inscription: Ven Avr 11, 2008 9:15 pm

Re: [Inform 6] Ecriture d'un fichier texte

Messagepar Mule hollandaise le Sam Fév 24, 2018 8:26 pm

Ah cool ! Un wordsize qui manque et un array de type string apparemment. Super !
Mule hollandaise
Grand Ancien
 
Messages: 1123
Inscription: Mar Aoû 29, 2006 10:57 pm

Re: [Inform 6] Ecriture d'un fichier texte

Messagepar Yoruk le Sam Fév 24, 2018 8:47 pm

Intéressant... Je suis en train de tester la méthode proposée dans la librairie "Achievements" indiquée par Mule. L'idée est de construire le buffer de sortie en redirigeant @output_buffer non pas vers l'écran mais vers un fameux buffer qu'on vient ensuite écrire avec @save. Mais j'ai encore des crashs... J'ai échangé quelques emails avec l'auteur de la librairie, mais en attendant je vais tester le code d'Auraes... :)

Extrait :
Code: Tout sélectionner
 @output_stream 3 ach_zfile_buf;
 
  print "Bonjour a tous";
   
  @output_stream -3;
  len = ach_zfile_buf-->0 + WORDSIZE; ! length is prepended to the ach data
   
  @save ach_zfile_buf len ach_filename_buf prompt -> result;
  if (~~result) {
      print "*** SavePersistentAchsZ: @@64save to '", (string) ach_filename, "' failed ***^";
      return;
Yoruk, SATOR AREPO TENET OPERA ROTAS
Avatar de l’utilisateur
Yoruk
Grand Ancien
 
Messages: 1065
Inscription: Lun Juin 11, 2007 9:50 am
Localisation: Chiddes, à 150 mètres du lavoir

Re: [Inform 6] Ecriture d'un fichier texte

Messagepar auraes le Sam Fév 24, 2018 9:20 pm

J'ai simplifié, dans la mesure ou cela semble limité à 255 octets + 1 octet pour la taille du buffer, inutile de compliqué.
Code: Tout sélectionner
!% -Cu
!% -v8
!% -~S

Array nom_fichier string "nom_fichier";

Array data_save string "Test de Save and Restore";
Array data_restore string 255;
   
[ main   key flag n i;
   n = data_save->0 + 1;

   @save data_save n nom_fichier -> flag;
   if (flag == 0) print "Save failed.^";

   @restore data_restore n nom_fichier -> flag;
   if (flag == 0) print "Restore failed.^";

   i = 0;
   while (i < n) {
      print (char) data_restore->i;
      i++;
   }
   new_line;
   .readkey;
   @read_char 1 ->key;
];
J'ai pas testé si le flag fonctionne.
Dernière édition par auraes le Sam Fév 24, 2018 10:12 pm, édité 1 fois.
Avatar de l’utilisateur
auraes
Grand Ancien
 
Messages: 348
Inscription: Ven Avr 11, 2008 9:15 pm

Re: [Inform 6] Ecriture d'un fichier texte

Messagepar auraes le Sam Fév 24, 2018 9:57 pm

Si tu veux utiliser @output_stream 3, ça change pas grand chose et visiblement les sauvegardes ne sont pas limitées à 256 octets !
Code: Tout sélectionner
!% -Cu
!% -v8
!% -~S

Array nom_fichier string "nom_fichier";

Array data_save buffer    1024;
Array data_restore buffer 1024;

[ main key flag len i;
   
   @output_stream 3 data_save;
   print "Thalassius vero ea tempestate praefectus praetorio praesens ipse quoque adrogantis ingenii, considerans incitationem eius ad multorum augeri discrimina, non maturitate vel consiliis mitigabat, ut aliquotiens celsae potestates iras principum molliverunt, sed adversando iurgandoque cum parum congrueret, eum ad rabiem potius evibrabat, Augustum actus eius exaggerando creberrime docens, idque, incertum qua mente, ne lateret adfectans. quibus mox Caesar acrius efferatus, velut contumaciae quoddam vexillum altius erigens, sine respectu salutis alienae vel suae ad vertenda opposita instar rapidi fluminis irrevocabili impetu ferebatur.";
   @output_stream -3;

   len = data_save-->0 + WORDSIZE;

   @save data_save len nom_fichier -> flag;
   if (flag == 0) print "Save failed.^";

   @restore data_restore len nom_fichier -> flag;
   if (flag == 0) print "Restore failed.^";

   i = 0;
   while (i < len) {
      print (char) data_restore->(WORDSIZE+i);
      i++;
   }
   new_line;
   .readkey;
   @read_char 1 ->key;
];
Par contre, si ça se passe bien avec Frotz, Gorgoyle(Frotz) ne prend pas en compte le nom du fichier, il m'affiche un 'Save failed' et me raffiche mon texte avec deux ?? à la fin.
*** Le problème vient de Gorgoyle(Frotz), avec Gorgoyle(Bocfel), ça fonctionne. ***
Avatar de l’utilisateur
auraes
Grand Ancien
 
Messages: 348
Inscription: Ven Avr 11, 2008 9:15 pm

Re: [Inform 6] Ecriture d'un fichier texte

Messagepar Yoruk le Dim Fév 25, 2018 10:17 am

Merci !

J'ai effectivement un save failed avec Gargoyle Frotz, rien avec Gargoyle Bocfel.

Par contre dans tout les cas le fichier de sauvegarde semble cohérent, j'ai juste un caractère étrange en début de fichier, qui ne semble d'ailleurs pas gêner la relecture. Dans les deux cas (Frotz et Bocfel) le texte s'affiche normalement.

Par contre, (dernier ?) problème : comment rebalancer X caractères de la array lue dans une variable ?

Code: Tout sélectionner
   i = 0;
   Variable = "";
   while (i < 5) {
      print (char) data_restore->(WORDSIZE+i);
      Variable = Variable + data_restore->(WORDSIZE+i);  !Je voudrais faire un truc comme ça...
      i++;
   }
Yoruk, SATOR AREPO TENET OPERA ROTAS
Avatar de l’utilisateur
Yoruk
Grand Ancien
 
Messages: 1065
Inscription: Lun Juin 11, 2007 9:50 am
Localisation: Chiddes, à 150 mètres du lavoir

Re: [Inform 6] Ecriture d'un fichier texte

Messagepar auraes le Dim Fév 25, 2018 10:56 am

Yoruk a écrit: j'ai juste un caractère étrange en début de fichier, qui ne semble d'ailleurs pas gêner la relecture.
C'est normal, puisque on sauvegarde aussi les 2 ou 4 (WORDSIZE) premiers octets du tableau qui sont la taille de celui-ci. Mais tu peux trés bien ne pas les sauvegarder.
Code: Tout sélectionner
!% -Cu
!% -v5
!% -~S

Array nom_fichier string "nom_fichier";

Array data_save    buffer 1024;
Array data_restore buffer 1024;


[ main key flag len i pt;
   
   @output_stream 3 data_save;
   print "Thalassius vero ea tempestate praefectus praetorio praesens ipse quoque adrogantis ingenii, considerans incitationem eius ad multorum augeri discrimina, non maturitate vel consiliis mitigabat, ut aliquotiens celsae potestates iras principum molliverunt, sed adversando iurgandoque cum parum congrueret, eum ad rabiem potius evibrabat, Augustum actus eius exaggerando creberrime docens, idque, incertum qua mente, ne lateret adfectans. quibus mox Caesar acrius efferatus, velut contumaciae quoddam vexillum altius erigens, sine respectu salutis alienae vel suae ad vertenda opposita instar rapidi fluminis irrevocabili impetu ferebatur.";
   @output_stream -3;

   len = data_save-->0;

   pt = data_save + WORDSIZE;
   @save pt len nom_fichier -> flag;
   if (flag == 0) print "Save failed.^";

   pt = data_restore + WORDSIZE;
   @restore pt len nom_fichier -> flag;
   if (flag == 0) print "Restore failed.^";

   data_restore-->0 = len;

   i = 0;
   while (i < len) {
      print (char) data_restore->(WORDSIZE+i);
      i++;
   }
   new_line;
   .readkey;
   @read_char 1 ->key;
];
Tu n'es pas non plus obligé de faire un tableau data_save et un tableau data_restore ; tu peux n'en faire qu'un. Et si tu utilises les bibliothèques, tu peux utiliser PrintToBuffer() au lieu de @output_stream 3/-3
Dernière édition par auraes le Mar Fév 27, 2018 3:29 pm, édité 1 fois.
Avatar de l’utilisateur
auraes
Grand Ancien
 
Messages: 348
Inscription: Ven Avr 11, 2008 9:15 pm

Re: [Inform 6] Ecriture d'un fichier texte

Messagepar auraes le Dim Fév 25, 2018 11:15 am

Yoruk a écrit:Par contre, (dernier ?) problème : comment rebalancer X caractères de la array lue dans une variable ?

Code: Tout sélectionner
!% -Cu
!% -v8
!% -~S

Array nom_fichier string "nom_fichier";

Array data_buf    buffer 1024;

Array MaVariable1 buffer 32;
Array MaVariable2 buffer 128;

[ memcpy src dest pos  i;
   i = 0;
   pos--;
   while (i < dest-->0 && pos < src-->0) {
      dest->(WORDSIZE+i) = src->(WORDSIZE+pos);
      i++;
      pos++;
   }
   dest-->0 = i;
];

[ print_txt buf  i;
   i = 0;
   while (i < buf-->0) {
      print (char) buf->(WORDSIZE+i);
      i++;
   }
];

[ main key flag len pt pos;
   
   @output_stream 3 data_buf;
   print "Thalassius vero ea tempestate praefectus praetorio praesens ipse quoque adrogantis ingenii, considerans incitationem eius ad multorum augeri discrimina, non maturitate vel consiliis mitigabat, ut aliquotiens celsae potestates iras principum molliverunt, sed adversando iurgandoque cum parum congrueret, eum ad rabiem potius evibrabat, Augustum actus eius exaggerando creberrime docens, idque, incertum qua mente, ne lateret adfectans. quibus mox Caesar acrius efferatus, velut contumaciae quoddam vexillum altius erigens, sine respectu salutis alienae vel suae ad vertenda opposita instar rapidi fluminis irrevocabili impetu ferebatur."; !635 caractères
   @output_stream -3;

   len = data_buf-->0;

   pt = data_buf + WORDSIZE; !pour ne pas sauvegarder la taille du tableau

   @save pt len nom_fichier -> flag;
   if (flag == 0) print "Save failed.^";

   @restore pt len nom_fichier -> flag;
   if (flag == 0) print "Restore failed.^";

   ! Je me positionne ou je veux commencer la copie dans mon data_buf
   
   pos = 20; ! Je commence la copie à la 20e lettre
   memcpy(data_buf, MaVariable1, pos);

   pos = 200; ! Je commence la copie à la 200e lettre
   memcpy(data_buf, MaVariable2, pos);

   print "Var 1 = ~", (print_txt) MaVariable1, "~^";
   print "Var 2 = ~", (print_txt) MaVariable2, "~^";

   new_line;
   .readkey;
   @read_char 1 ->key;
];
*** cette fois ça doit être bon ! ***
Avatar de l’utilisateur
auraes
Grand Ancien
 
Messages: 348
Inscription: Ven Avr 11, 2008 9:15 pm


Retourner vers Questions techniques et aide pour votre code

Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 1 invité

cron