sprinft a base de tableau

sprinft a base de tableau - C - Programmation

Marsh Posté le 03-03-2008 à 21:55:57    

Bonjour à tous,
 
je souhaiterais faire un petit module de generation de fichier configurable. En fait j'ai un structure de donnée de type liste chainée qui contient une structure de type (ce n'est pas le vrai code, car c'est une structure de donnée fournie par un progiciel qui est un type abstrait, mais c'est juste pour l'exemple.)
 

Code :
  1. typedef struct __maillon {
  2.      char * name;
  3.      char * value;
  4.      struct __maillon * m_nextp;
  5. } maillon;


 
Structurellement les "name" sont uniques dans une liste donnée...
 
Ensuite je souhaite faire un génarateur de fichier configurable qui contient dans la conf :
- le format au format printf (avec des %s "toutes options", avec les -, padding à droite, etc...)
- la liste des paramètres (les "names" des maillons) pour remplacer les %s avec la valeur correspondante de maillons de chaine
- la taille max resultante (pour ne pas avoir à me faire chier avec des realloc)
 
Pour cela j'avais pensé à un moyen relativement générique de passer d'une fonction de type :

Code :
  1. int my_sprintf_array(char * buf, char * fmt, int nb_params,char ** params_array)

 
qui appellerait comme il faut (v)sprintf, mais je ne vois pas trop comment faire sans me taper un redécoupage de mon chaine de formattage : mais je ne vois pas comment faire pour passer de ce tableau de chaines à un va_list ou tout autres choses, et je suis à cours d'idées
 
Merci d'avance pour toute idée


Message édité par dreameddeath le 03-03-2008 à 22:23:36
Reply

Marsh Posté le 03-03-2008 à 21:55:57   

Reply

Marsh Posté le 04-03-2008 à 11:56:54    

__ sont des identifiants réservés. Tu ne dois pas les utiliser.

Reply

Marsh Posté le 04-03-2008 à 23:28:59    

Merci pour le conseil, je le saurais pour la prochaine fois...
 
Mais je ne présentais la struct (que j'ai écris à la volée) que pour le principe, sachant que mon vrai problème, c'est de partir d'une liste de chaine (récupérée depuis les valeurs de la liste chainée) en utilisant un formattage à la sauce sprintf...
 
par exemple, un fichier de conf  contenant

Code :
  1. fields=NAME_1|NAME_2|NAME_TEST1
  2. fmt=%-20.20s,%10s\n%15s
  3. taille=500


 
et un liste chainée du type (pseudo code)

Code :
  1. void main(){
  2.     maillon maillon1,maillon2,maillon3,maillon4;
  3.     char ** list_values;
  4.     int nb_params;
  5.     int taille_buf;
  6.     char ** fields;
  7.     char * fmt;
  8.     char * buffer;
  9.     if(!read_conf_file(&fields,&nb_params, &fmt,&taille_buf){
  10.         /* gestion erreur */
  11.     }
  12.     list_values = malloc(nb_params*sizeof(char *));
  13.     if(list_values == NULL){
  14.         /* gestion d'erreur */
  15.     }
  16.     /*  
  17.        mes malloc des strings des maillons, du buffer de sortie
  18.     ...
  19.     */
  20.    /* init maillon 1*/
  21.    strcpy(maillon1.name,"NAME1" );
  22.    strcpy(maillon1.value,"test" );
  23.    maillon1.m_nextp = &maillon2;
  24.    /* init maillon 2*/
  25.    strcpy(maillon2.name,"NAMETOTO1" );
  26.    strcpy(maillon2.value,"test_toto1" );
  27.    maillon2.m_nextp = &maillon3;
  28.    /* init maillon 3*/
  29.    strcpy(maillon3.name,"NAME_TEST1" );
  30.    strcpy(maillon3.value,"test_name1" );
  31.    maillon3.m_nextp = &maillon4;
  32.    /* init maillon 4*/
  33.    strcpy(maillon4.name,"NAME_2" );
  34.    strcpy(maillon4.value,"test" );
  35.    maillon4.m_nextp = NULL;
  36.    /*  
  37.    remplissage de list values en fonction de "fields" et des maillons
  38.    ...
  39.    */
  40.  
  41.    my_sprinft_array(buffer, fmt,nb_params,list_values);
  42.    printf(buffer);


 
par contre je ne vois pas trop comment faire pour passer de my_sprintf_array à (v)sprintf sans faire de parsing sioux du contenu de la chaine fmt lu dans la conf...
 
A moins que vous ayez une autre approche + simple...
 
J'espère que je suis assez clair


Message édité par dreameddeath le 04-03-2008 à 23:41:06
Reply

Marsh Posté le 05-03-2008 à 01:16:11    

Bon bah finalement, j'ai fait un petit truc qui est finalement plus simple que prévu, et ça marche pas mal...
 
En fait je par le format en faisant :
- boucle sur les '%'
- je copie dans le buffer de sortie tout ce que j'ai "sauté" en faisant ma recherche du % suivant
- si le caractère suivant est % (donc je suis en train de traiter un %%) j'affiche %, j'avance et je boucle
- sinon je cherche le prochain "s" (assumption, le format est correct), et j'appelle sprinft dessus (certes un peu sioux en faisant un décalage sur le buf de la longueur courante de ce que j'ai déjà écris)
- j'avance d'un caractère (par rapport à la fin du format de string et je boucle
- en sortant de boucle je copie le résiduel s'il existe
- je checke que j'ai bien "consommé" tout mes paramètres sinon j'affiche un warning...
 
Voilà le code :

Code :
  1. int my_sprintf_array(char * buf,char * fmt, int nb_params, char ** array_values){
  2.     char *fmt_curr_p = fmt;
  3.     char *last_pos_fmt = fmt;
  4.     char sub_fmt_p[10]="";/*assumption not more than 10 char for the %[fmt]s string format*/
  5.     int curr_param_pos = 0;
  6.    
  7.    
  8. #ifdef DEBUG
  9.     printf("starting to process\n" );
  10. #endif
  11.     /*clean the buffer*/
  12.     strcpy(buf,"" );
  13.     /*start loop on % chars*/
  14.     while(fmt_curr_p=strpbrk(fmt_curr_p,"%" )){
  15.         /*copy all the char from last pos to the new one excepted*/
  16.         strncat(buf,last_pos_fmt,fmt_curr_p-last_pos_fmt);
  17.         last_pos_fmt=fmt_curr_p;
  18. #ifdef DEBUG       
  19.         printf("new buffer is '%s'\n",buf);
  20. #endif       
  21.         /*if next char is a %, it's a protection */
  22.         if(strncmp((fmt_curr_p+1),"%",1)==0){
  23.             /*add % in the buf and move forward to skip those two*/
  24.             strcat(buf,"%" );
  25. #ifdef DEBUG
  26.             printf("append '%%', new buffer is '%s'\n",buf);
  27. #endif
  28.             fmt_curr_p+=2;   
  29.             last_pos_fmt = fmt_curr_p;
  30.             continue;
  31.         }
  32.        
  33.         /*try to find the end of the formatting*/
  34.         fmt_curr_p=strpbrk(fmt_curr_p,"s" );
  35.        
  36.         /*end of string not found*/
  37.         if(fmt_curr_p==NULL){
  38.             fprintf(stderr,"Error wrong format in fmt :\n'%s'.\n The char %% found without s after. Please put a %%%% for the %% char\n",fmt);
  39.             return 1;
  40.         }
  41.        
  42.         /*not enough parameters*/
  43.         if(curr_param_pos >= nb_params){
  44.             fprintf(stderr,"Not enough strings at least %d required and %d found\n",curr_param_pos,nb_params);
  45.             return 1;
  46.         }
  47.         /*clean and copy the %s format into the string*/
  48.         strcpy(sub_fmt_p,"" );
  49.         strncat(sub_fmt_p,last_pos_fmt,fmt_curr_p-last_pos_fmt+1);
  50. #ifdef DEBUG
  51.         printf("the found format is '%s'\n",sub_fmt_p);
  52. #endif           
  53.         /*sprintf to the end of the current buffer (pos = strlen(buf))*/
  54.         sprintf(buf+strlen(buf),sub_fmt_p,array_values[curr_param_pos]);
  55.        
  56. #ifdef DEBUG
  57.         printf("the new buffer is '%s'\n",buf);
  58. #endif       
  59.         /*change of input string param*/
  60.         curr_param_pos++;
  61.         /*move to the next char of the input fmt*/
  62.         fmt_curr_p++;
  63.         last_pos_fmt=fmt_curr_p;
  64.     }/*end loop while % are found*/
  65.    
  66.    
  67.     /*copy the last part of the format if not empty*/
  68.     if(strlen(last_pos_fmt)!=0){
  69.         strcat(buf,last_pos_fmt);
  70.     }
  71.    
  72.     /*checking the consumption of all params consumption*/
  73.     if(curr_param_pos!=nb_params){
  74.         fprintf(stderr, "Warning : All parameters not consumed (%d on %d)\n",curr_param_pos,nb_params);
  75.     }
  76.    
  77.     /*say that everything was ok*/
  78.     return 0;
  79. }/*end of my_sprintf_array*/


 
Voilà, si ça peut aider,intéresser d'autres,
 
Je suis preneur de remarques/autres idées...


Message édité par dreameddeath le 05-03-2008 à 01:23:13
Reply

Marsh Posté le 05-03-2008 à 11:09:44    

bah t'es .name et .value ne sont pas alloués ...

Reply

Marsh Posté le 05-03-2008 à 11:49:40    

je sais : c'est "caché" dans les commentaires (je voulais pas écrire tous les mallocs)...
 
Le code en question n'était qu'un exemple de ce que je voulais faire, ma vrai problématique étant la fonction my_sprintf_array, qui s'est avérée plus simple que prévue (en fait je me battais avec les strtok, alors que mon vrai besoin était la fonction strpbrk)...


Message édité par dreameddeath le 05-03-2008 à 11:50:26
Reply

Marsh Posté le 05-03-2008 à 11:57:04    

strncmp((fmt_curr_p+1),"%",1) c'est une sacré façon de faire un ==
 
Dans tous les cas, croisons les doigts pour que buf soit assez grand.

Reply

Marsh Posté le 05-03-2008 à 12:16:23    

ce sont les risques du métier en C : je voulais surtout faire un sprintf non basé sur un nombre de params variables, mais un tableau de valeur construit par l'appelant

Reply

Marsh Posté le 05-03-2008 à 12:18:50    

dreameddeath a écrit :

ce sont les risques du métier en C

C'est pas parce que ton métier est risqué qu'il faut aller sur le chantier en slip-chaussettes.

Reply

Marsh Posté le 05-03-2008 à 18:37:26    

Donc pour éviter le slip chaussette, j'ai modifié mon code pour checker la taille au fur et à mesure, j'en ai profité pour assouplir le passage de paramètre en pouvant passer 3 types (int, float et string) et des codes retours normalisés ...
 
Je pense (j'espère?) que c'est bon maintenant
 
Taz, je te laisse seul juge :)
 

Code :
  1. /* Return Code Definition */
  2. typedef enum  {
  3.     MY_SPRINTF_OK=0,
  4.     MY_SPRINTF_ERR_BUF_SIZE=1,
  5.     MY_SPRINTF_ERR_SYNTAX=2,
  6.     MY_SPRINTF_ERR_PARAMS=3,
  7.     MY_SPRINTF_ERR_FMT_SIZE=4
  8. } my_sprintf_errcode ;
  9. my_sprintf_errcode my_sprintf_array(char * buf,int buf_max_len, char * fmt, int nb_params, void ** array_values){
  10.     char *fmt_curr_p = fmt;
  11.     char *last_pos_fmt = fmt;
  12.     char sub_fmt_p[MAX_FMT_STATEMENT_LEN+1]="";
  13.     my_sprintf_errcode ret_code = MY_SPRINTF_OK;
  14.     int curr_param_pos = 0;
  15.     int remaining_len = buf_max_len - 1; //already take into account the \0
  16.     int appened_str_len = 0;
  17.     int fmt_str_len = 0;
  18.    
  19.     /*clean the buffer*/
  20.     strcpy(buf,"" );
  21.    
  22.     /*start loop on % chars if buffer has still place */
  23.     while((remaining_len>=0) && (fmt_curr_p=strpbrk(fmt_curr_p,"%" ))){
  24.         /*determine the part len to copy*/
  25.         appened_str_len = fmt_curr_p-last_pos_fmt;
  26.         /*compute the future remaining len*/
  27.         remaining_len -= appened_str_len;
  28.         /*check buf remaining size*/
  29.         if((remaining_len)<0){
  30.             ret_code = MY_SPRINTF_ERR_BUF_SIZE;
  31.             break;
  32.         }
  33.        
  34.         /*copy all the char from last pos to the new one excepted*/
  35.         strncat(buf,last_pos_fmt,appened_str_len);
  36.         last_pos_fmt=fmt_curr_p;
  37.         /*if next char is a %, it's a protection */
  38.         if(*(fmt_curr_p+1)=='%'){
  39.             remaining_len-=1;
  40.             /*check remaining len minus one char (%)*/
  41.             if((remaining_len)<0){
  42.                 ret_code = MY_SPRINTF_ERR_BUF_SIZE;
  43.                 break;
  44.             }
  45.             /*add % in the buf*/
  46.             strcat(buf,"%" );
  47.             /*move forward to skip the %% */
  48.             fmt_curr_p+=2;
  49.             last_pos_fmt = fmt_curr_p;
  50.             continue;
  51.         }
  52.         /*it is a format*/
  53.         else{
  54.             /*try to find the end of the formatting*/
  55.             fmt_curr_p=strpbrk(fmt_curr_p,"sdf" );
  56.            
  57.             /*end of parameter not found*/
  58.             if(fmt_curr_p==NULL){
  59.                 fprintf(stderr,"Error wrong format in fmt :\n'%s'.\n The char %% found without s or f or d after. Please put a %%%% for the %% char\n",fmt);
  60.                 ret_code = MY_SPRINTF_ERR_SYNTAX;
  61.                 break;
  62.             }
  63.            
  64.             /*not enough parameters*/
  65.             if(curr_param_pos >= nb_params){
  66.                 fprintf(stderr,"Not enough strings at least %d required and %d found\n",curr_param_pos,nb_params);
  67.                 ret_code = MY_SPRINTF_ERR_PARAMS;
  68.                 break;
  69.             }
  70.            
  71.             /*clean and copy the %s format into the string*/
  72.             strcpy(sub_fmt_p,"" );
  73.             /*check the format size*/
  74.             fmt_str_len = fmt_curr_p-last_pos_fmt+1;
  75.             if(fmt_str_len > MAX_FMT_STATEMENT_LEN){
  76.                 fprintf(stderr,"A format rule '%*.*s' is two big\n",fmt_str_len,fmt_str_len,last_pos_fmt);
  77.                 ret_code = MY_SPRINTF_ERR_FMT_SIZE;
  78.                 break;
  79.             }
  80.             strncat(sub_fmt_p,last_pos_fmt,fmt_str_len);
  81.        
  82.             /*snprintf to the end of the current buffer (pos = strlen(buf))*/
  83.             /*the max size is the remaining size +1 (due to count of \n)*/
  84.             switch(*fmt_curr_p){
  85.                 case 's':
  86.                     appened_str_len = snprintf(buf+strlen(buf),remaining_len+1,sub_fmt_p,(char*)array_values[curr_param_pos]);
  87.                     break;
  88.                 case 'd' :
  89.                     appened_str_len = snprintf(buf+strlen(buf),remaining_len+1,sub_fmt_p,*((int*)array_values[curr_param_pos]));
  90.                     break;
  91.                 case 'f' :
  92.                     appened_str_len = snprintf(buf+strlen(buf),remaining_len+1,sub_fmt_p,*((float*)array_values[curr_param_pos]));
  93.                     break;
  94.             }
  95.            
  96.             /*check the snprinft max size reached */
  97.             if(appened_str_len < 0){
  98.                 ret_code = MY_SPRINTF_ERR_BUF_SIZE;
  99.                 break;
  100.             }
  101.             else{
  102.                 remaining_len-=appened_str_len;
  103.             }
  104.            
  105.             /*change of input string param*/
  106.             curr_param_pos++;
  107.             /*move to the next char of the input fmt*/
  108.             fmt_curr_p++;
  109.             last_pos_fmt=fmt_curr_p;
  110.         }/*end of fmt string par management*/
  111.        
  112.     }/*end loop while % are found*/
  113.    
  114.     /* If no errors print the residual part if any*/
  115.     if(ret_code == MY_SPRINTF_OK){
  116.         /*copy the last part of the format if not empty*/
  117.         appened_str_len = strlen(last_pos_fmt);
  118.         remaining_len -= appened_str_len;
  119.         /*size check*/
  120.         if(remaining_len<0){
  121.             ret_code = MY_SPRINTF_ERR_BUF_SIZE;
  122.         }
  123.         else if(appened_str_len!=0){
  124.             strcat(buf,last_pos_fmt);
  125.         }
  126.     }
  127.    
  128.    
  129.     /*Errors management*/
  130.     if(ret_code != MY_SPRINTF_OK){
  131.         switch(ret_code){
  132.             case MY_SPRINTF_ERR_BUF_SIZE :
  133.                 fprintf(stderr, "Error MY_SPRINTF_ERR_BUF_SIZE occurs.\n" );
  134.                 break;
  135.             case MY_SPRINTF_ERR_PARAMS :
  136.                 fprintf(stderr, "Error MY_SPRINTF_ERR_PARAMS occurs.\n" );
  137.                 break;
  138.             case MY_SPRINTF_ERR_SYNTAX :
  139.                 fprintf(stderr, "Error MY_SPRINTF_ERR_SYNTAX occurs.\n" );
  140.                 break;
  141.             case MY_SPRINTF_ERR_FMT_SIZE :
  142.                 fprintf(stderr, "Error MY_SPRINTF_ERR_FMT_SIZE occurs.\n" );
  143.                 break;
  144.             default:
  145.                 fprintf(stderr, "An unknown Error occurs.\n" );
  146.                
  147.         }
  148.         fprintf(stderr, "The full format was : %s.\n",fmt);
  149.         fprintf(stderr, "The real processed format is '%*.*s'\n",last_pos_fmt-fmt,last_pos_fmt-fmt,fmt);
  150.     }
  151.     /*if no errors checking the consumption of all params consumption*/
  152.     else if(curr_param_pos!=nb_params){
  153.         fprintf(stderr, "Warning : All parameters not used (%d used on %d)\n",curr_param_pos,nb_params);
  154.     }
  155.    
  156.     /*teel the final result*/
  157.     return ret_code;
  158. }/*end of my_sprintf_array*/


 
J'espère n'avoir rien oublié cette fois ;p


Message édité par dreameddeath le 05-03-2008 à 18:38:43
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed