Parser Ligne de Commande MFC (WinMain)

Signaler
Messages postés
1662
Date d'inscription
lundi 16 septembre 2002
Statut
Membre
Dernière intervention
30 juillet 2008
-
Messages postés
7
Date d'inscription
mercredi 5 octobre 2005
Statut
Membre
Dernière intervention
1 novembre 2007
-
Bonjour,



J'ai ceci :

int WINAPI WinMain( HINSTANCE hInstance,

HINSTANCE hPrevInstance,


LPTSTR
lpCmdLine,



int nCmdShow)



Je souhaite obtenir les arguments un peu comme argc et argv à partir de lpCmdLine. C'est à dire en passant les arguments suivant

bonjour "test allo.txt"

je dois récupérer en premier seulement "bonjour" et ensuite "test allo.txt".

Mon programme est pour WindowsCE, donc je suis extrêmement limité,
parser par espace n'est pas une solution je crois car s'il y a des
guillemets ça ne marchera pas, et si ceux-ci sont échappé? ("test
"allo.txt")


Cette fonction ne m'est pas disponible : CommandLineToArgvW

Et je suis extrèmement limité sur l'utilisation de la STLport



Si vous avez une idée, je suis preneur !!! merci




, EssayezTestez avant de Poser une question !
http://www.lookstrike.com

19 réponses

Messages postés
1878
Date d'inscription
jeudi 16 octobre 2003
Statut
Membre
Dernière intervention
16 mars 2011
1
tu as ta ligne ds une chaine



y te suffit simplement d'utiliser qqch comme ceci



CString param,txt=lpCmdLine;

l=strlen(lpCmdLine);

for(i=0;i<l;i++)
{

param="";

if(lpCmdLine[i]=='"')

param=getChaine(txt,&i);

else

while(i<l&&lpCmdLine[i]!=' ')

param+=lpCmdLine[i++];

traiterParam(param);

}







inline CString recupTxt(const CString &code, unsigned int *ptrCode)const

{

/// ---------------------------------------------------------------------------------------------------------------

/// ---------------- recupTxt(const BString& code ,unsigned int* ptrCode) -> BString ----------------

/// ---------------------------------------------------------------------------------------------------------------

/// ----- Objectif : récupération d'une chaîne de texte

/// ----- Auteur(s) : Magic Nono 22/07/03

/// ----- PreCond : ptr pointe sur '\'' ou '"'

/// ----- PostCond : ptr pointe sur le '\'' ou '"' correspondant (après txt...)

/// ----- Etat :
1
(-1<0<1<2)

/// ----- MaJ 20/08/04 : car codé en hexa

/// ----- MaJ 15/07/05 : accélération - passage en inline

/// ---------------------------------------------------------------------------------------------------------------

/// ----- const CString& code : source

/// ----- unsigned int* ptrCode : ptr sur le source

/// ---------------------------------------------------------------------------------------------------------------

/// ----- retour (CString) : le texte (avec ses delimiteurs)

/// ---------------------------------------------------------------------------------------------------------------

/// ----- Var Muettes (cf.partie préc) (2) : code, ptrCode

/// ----- Var Internes à la fonction (4) : c, i, l, txt

/// ----- Var Utilisées par adresse (1) : code

/// ----- Var In (1) : code

/// ----- Var In-Out (1) : ptrCode

unsigned int i=*ptrCode,l=code.getLength();

ASSERT(i<l);

char c=code[i];

//if(c!='\'' && c!='"')
PB1("mauvaise utilisation de recupTxt\nPartie Mise
en Forme");

ASSERT(c=='\'' || c=='"');

BString txt=c;

if(c=='\'')

{

/// algo : caractère (ou code hexa)

c=code[++i];

txt+=c;

if(c=='\\')

txt+=code[++i]; //car à sauter

c=code[++i];

///algo : cas hexa en caractere (new 20/08/04)

if(txt=="'\\x")

{

static BString nb="0123456789ABCDEFabcdef";

while(nb.checkIn(code[i++]))

txt+=code[i-1];

i--;

c=code[i];

}

if(c!='\'')

PB1("erreur syntaxique : pb de quote\nPartie Mise en Forme");

txt+=c;

}

else

{

/// algo : {c='"'}

/// algo : chaîne

c='!';

for(i++;i<l && (c!='"');i++)

{

c=code[i];

txt+=c;

if(c=='\\')

txt+=code[++i]; //car à sauter

}

i--;

}

*ptrCode=i;

return txt;

}

éventuellt règle les pb de unicode/ansi et basta
___________________________________________________________
Magicalement
Nono
Messages postés
1878
Date d'inscription
jeudi 16 octobre 2003
Statut
Membre
Dernière intervention
16 mars 2011
1
remplace BString par CString

___________________________________________________________
Magicalement
Nono
Messages postés
1878
Date d'inscription
jeudi 16 octobre 2003
Statut
Membre
Dernière intervention
16 mars 2011
1
et cette fonction doit etre optimisable,

d'ailleur si qqn propose plus optimisé que ça ac les mm fonctionnalité, je suis fort intéressé



(pas en assmb stp BN)

___________________________________________________________
Magicalement
Nono
Messages postés
1878
Date d'inscription
jeudi 16 octobre 2003
Statut
Membre
Dernière intervention
16 mars 2011
1
oups, ds mon, premier poste, évidement,

getChaine=recupTxt



....

___________________________________________________________
Magicalement
Nono
Messages postés
1878
Date d'inscription
jeudi 16 octobre 2003
Statut
Membre
Dernière intervention
16 mars 2011
1
en fait, il faudrait optimiser cette fonc


/// ----- Objectif : récupération d'une chaîne de texte

/// ----- PreCond : ptr pointe sur '\'' ou '"'

/// ----- PostCond : ptr pointe sur le '\'' ou '"' correspondant (après txt...)

/// ----- Etat :
1
(-1<0<1<2)

/// ---------------------------------------------------------------------------------------------------------------

/// ----- const char* code : source

/// ----- unsigned int* ptrCode : ptr sur le source

/// ---------------------------------------------------------------------------------------------------------------

/// ----- retour (String) : le texte (avec ses delimiteurs)



voir mm encore mieux



/ ----- Objectif : récupération d'une chaîne de texte

/// ----- PreCond : ptr pointe sur '\'' ou '"'

/// ----- PostCond : ptr pointe sur le '\'' ou '"' correspondant (après txt...)

/// ----- Etat :
1
(-1<0<1<2)

/// ---------------------------------------------------------------------------------------------------------------

/// ----- const char* code : source

/// ----- const unsigned int* ptrCode : ptr sur le source

/// ---------------------------------------------------------------------------------------------------------------

/// ----- retour ( unsigned int ) : ptr en fin de chaine ds le srce




___________________________________________________________
Magicalement
Nono
Messages postés
1662
Date d'inscription
lundi 16 septembre 2002
Statut
Membre
Dernière intervention
30 juillet 2008
1
Bon j'avais écrit un message et comme d'hab, la foutu erreur 500 me l'a perdu...

Je disais qu'on dirait que ca ne s'applique pas à ce que je veux..
peut-etre je ne comprends pas la fonction ou jsais pas quoi... je l'ai
adapté pour qu'elle fonctionne avec CE...

CheckIn par Find !=-1, [i] par GetAt(i)...



Je voudrais une fonction

func("salut 'bonjour \' haha' test", 1) me retourne "bonjour ' haha"



En2k, si je trouve pas c'est pas plus grave j'implémenterai pas cette option...



Merci

, EssayezTestez avant de Poser une question !
http://www.lookstrike.com
Messages postés
1878
Date d'inscription
jeudi 16 octobre 2003
Statut
Membre
Dernière intervention
16 mars 2011
1
C ce que fait la fonction donnée plus haut


___________________________________________________________
Magicalement
Nono
Messages postés
1662
Date d'inscription
lundi 16 septembre 2002
Statut
Membre
Dernière intervention
30 juillet 2008
1
Eh bien je ne sais pas comment l'utiliser alors...

, EssayezTestez avant de Poser une question !
http://www.lookstrike.com
Messages postés
1878
Date d'inscription
jeudi 16 octobre 2003
Statut
Membre
Dernière intervention
16 mars 2011
1
inline CString recupTxt(const CString &code, unsigned int *ptrCode)const;

int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
CString param,txt=lpCmdLine;
unsigned cpt=1,l=strlen(lpCmdLine);
for(i=0;i<l;i++)
{
param="";
switch(lpCmdLine[i])
{
case ' ':
case '\t':
break;
case '"':
case '\'':
param=recupTxt(txt,&i);
break;
default:
while(i<l&&lpCmdLine[i]!=' ')
param+=lpCmdLine[i++];
}
printf("\t%d parametre : %s\n",cpt++,param);
}
return 0;
}

inline CString recupTxt(const CString &code, unsigned int *ptrCode)const
{
/// ---------------------------------------------------------------------------------------------------------------
/// ---------------- recupTxt(const BString& code ,unsigned int* ptrCode) -> BString ----------------
/// ---------------------------------------------------------------------------------------------------------------
/// ----- Objectif : récupération d'une chaîne de texte
/// ----- Auteur(s) : Magic Nono 22/07/03
/// ----- PreCond : ptr pointe sur '\'' ou '"'
/// ----- PostCond : ptr pointe sur le '\'' ou '"' correspondant (après txt...)
/// ----- Etat : 1 (-1<0<1<2)
/// ----- MaJ 20/08/04 : car codé en hexa
/// ---------------------------------------------------------------------------------------------------------------
/// ----- const CString& code : source
/// ----- unsigned int* ptrCode : ptr sur le source
/// ---------------------------------------------------------------------------------------------------------------
/// ----- retour (CString) : le texte (avec ses delimiteurs)
/// ---------------------------------------------------------------------------------------------------------------
/// ----- Var Muettes (cf.partie préc) (2) : code, ptrCode
/// ----- Var Internes à la fonction (4) : c, i, l, txt
/// ----- Var Utilisées par adresse (1) : code
/// ----- Var In (1) : code
/// ----- Var In-Out (1) : ptrCode
unsigned int i=*ptrCode,l=code.GetLength();
ASSERT(i<l);
char c=code[i];
//if(c!='\'' && c!='"') PB1("mauvaise utilisation de recupTxt\nPartie Mise en Forme");
ASSERT(c=='\'' || c=='"');
CString txt=c;
if(c=='\'')
{
/// algo : caractère (ou code hexa)
c=code[++i];
txt+=c;
if(c=='\\')
txt+=code[++i]; //car à sauter
c=code[++i];
/*
///algo : cas hexa en caractere (new 20/08/04)
if(txt=="'\\x")
{
static BString nb="0123456789ABCDEFabcdef";
while(nb.checkIn(code[i++]))
txt+=code[i-1];
i--;
c=code[i];
}
*/ if(c!='\'')
printf("\n\nerreur syntaxique : pb de quote\nPartie Mise en Forme\n\n");
txt+=c;
}
else
{
/// algo : {c='"'}
/// algo : chaîne
c='!';
for(i++;i<l && (c!='"');i++)
{
c=code[i];
txt+=c;
if(c=='\\')
txt+=code[++i]; //car à sauter
}
i--;
}
*ptrCode=i;
return txt;
}

___________________________________________________________
Magicalement
Nono
Messages postés
1100
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
17 octobre 2012
7
Bonjour,



Voilà le code que j'ai fait sur défi lancé par magic_nono il est sous
forme d'un header .hpp c'est la forme que je conseille. Tu l'inclu et
tu appelle la fonction comme il est démontré dans l'en-tête.

Merci de laisser mon nom c'est tout ce que je demande.



Restriction : Chaque argument doit être en guillemets en sachant que
sous Windows le nom de l'executable n'est pas compris dans les
arguments de lpCmdLine.



/*

Name: detectparam.hpp

Copyright: SCV

Author: Coasne Victor

Date: 05/08/05 17:00

Description: Extraire les paramètres d'une chaîne 1D pour les mettre

dans une chaîne en 2D

Utilisation:


int nombrearguments = detectnbparam(lpCmdLine);

char**argparam = extraitparam(lpCmdLine);

for (int i= 0;i<nombrearguments;i++)

{


cout << argparam[i] << endl;

}

Attention :


Chaque argument doit être dans des guillemets
séparés


*/



int detectnbparam(char*chaineadectect)

{

int nbparam=0;

for (int i=0;i<strlen(chaineadectect);i++)

{

if (chaineadectect[i]=='"') nbparam++;

}

return nbparam/2;

}



void extraireunparam(char*chainearemplir,int premierguillemet, int dernierguillemet,

char*chaineadectect)

{

for (int i=0;i<(dernierguillemet-premierguillemet)-1;i++)

{

chainearemplir[i]=chaineadectect[premierguillemet+1+i];

chainearemplir[i+1]='\0';

}

int len = strlen(chaineadectect);

for (int i=0;i<len-dernierguillemet;i++)

{

chaineadectect[i]=chaineadectect[dernierguillemet+1+i];

chaineadectect[i+1]='\0';

}

}



char** extraitparam(char*chaineadectect)

// Extraire les paramètres

// argparam -> Ne passer qu'un char** car c'est là où la mémoire est alloué pour

// y mettre les paramètres séparés en un tableau 2D de caractères

// chaineadectect -> La chaîne qui contient les paramètre qui doivent tous être

// entre guillemets

{

char ** argparam;

int nbparam=detectnbparam(chaineadectect);

int taillechaine=1024;

argparam=new char*[nbparam];

for (int i=0;i<nbparam;i++)

argparam[i]=new char[taillechaine];

for (int i=0;i<nbparam;i++)

{

int premierguillemet=-1,dernierguillemet=-1;

for (int y=0;y<strlen(chaineadectect);y++)

{

if (premierguillemet==-1)

{

if (chaineadectect[y]=='"')


premierguillemet=y;


}

else if(dernierguillemet==-1)

{

if (chaineadectect[y]=='"')

{


dernierguillemet=y;


extraireunparam(argparam[i],premierguillemet,dernierguillemet,chaineadectect);

y=strlen(chaineadectect);

}

}

}

}

return argparam;

}





Merci,



Le créateur du site http://victorlogiciels.com
Messages postés
1878
Date d'inscription
jeudi 16 octobre 2003
Statut
Membre
Dernière intervention
16 mars 2011
1
oui, Vic, C quasi ça



sauf que les elts sont soit des mots (ens de car)

soit des chaines (entre guillemet)



le 1er cas a traiter en + et C parfait

___________________________________________________________
Magicalement
Nono
Messages postés
1662
Date d'inscription
lundi 16 septembre 2002
Statut
Membre
Dernière intervention
30 juillet 2008
1
Je test ca lundi à la job et je vous reviens la dessus :)

Merci

, EssayezTestez avant de Poser une question !
http://www.lookstrike.com
Messages postés
1100
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
17 octobre 2012
7
Bonjour,



Citation : en sachant que sous Windows le nom de l'executable n'est pas compris dans les arguments de lpCmdLine

En réponse à : sauf que les elts sont soit des mots (ens de car)

soit des chaines (entre guillemet)

Complément : Comme tous les params peuvent être perso on les sépare tous.



PETIT PROGRAMME TEST POUR AIDER GRenard.

Il marche impect sous Dev-C++ :

#include

#include <stdlib.h>

using namespace std;

#include "detectparam.hpp"



int main()

{

char lpCmdLine[]=""arg1" "arg2" "arg3""arg4"";

/*

L'arg1 est séparé du 2 par un espace qui est séparé du 3 par 3 espaces
qui est séparé du 4 par rien Tous les arguments sont entre guillemets
les espaces (à l'intérieur des guillemets) sont pris en compte */




int nombrearguments = detectnbparam(lpCmdLine);

char**argparam = extraitparam(lpCmdLine);

for (int i= 0;i<nombrearguments;i++)

{


cout << argparam[i] << endl;

}

cout << "\n\n\n";

system("pause");

}






Merci,



Le créateur du site http://victorlogiciels.com
Messages postés
7
Date d'inscription
mercredi 5 octobre 2005
Statut
Membre
Dernière intervention
1 novembre 2007

Ton problème revient a écrire un compilateur, uniquement les parties lexicales et syntaxiques. Grosso Modo, il faut reconnaître dans une chaîne les parties entre espace si il n'y a pas eu avant un espace suivie d'un double quote et les parties entre espace suivie d'un double quote et d'un double quote suivie d'un espace comme avec les commandes windows. Pour résoudre se problème, il suffit d'écrire un automate (avantage: il termine toujours). Pour les besions de ton code, j'ai passé sous silence la partie allocation de la mémoire pour les chaînes de caractères extraites mais on peut trés bien sans passé.

char tabItem[30][20], c;
int j, k, i, etat;
etat = 0;
i = 0;
j = 0;
k = 0;
while (etat != 2) {
c = ligCommande[i];
switch (etat) {
case 0:
switch (c) {
case ' ':
case '\9':
break;
case '"':
etat = 3;
break;
case '\0' :
tabItem[j][k] = '\0';
etat = 2;
break;
default:
tabItem[j][k] = c;
k++;
etat = 1;
}
break;
case 1:
switch (c) {
case ' ':
case '\9':
tabItem[j][k] = '\0';
j++;
k = 0;
etat = 1;
break;
case '\0':
tabItem[j][k] = '\0';
etat = 2;
break;
default:
tabItem[j][k] = c;
k++;
}
break;
case 2:
break;
case 3:
switch (c) {
case '"':
etat = 4;
break;
case '\0':
tabItem[j][k] = '\0';
etat = 2;
break;
default:
tabItem[j][k] = c;
k++;
}
break;
case 4:
switch (c) {
case ' ':
case '\9':
tabItem[j][k] = '\0';
j++;
k = 0;
etat = 0;
break;
case '\0':
tabItem[j][k] = '\0';
etat = 2;
break;
default:
tabItem[j][k] = ligCommande[i-1];
k++;
tabItem[j][k] = c;
k++;
etat = 3;
}
}
i++;
}

Avec ce code tu peux extraire par exemple dans la chaîne '/DEBUG=5 "Tu es" Dans"Ton meilleur' les items suivants (en automate, on parle d'item) /DEBUG=5, Tu es, Dans"Ton meilleur. Le gateau sur la cerise, c'est qu'il n'a aucunement besion d'optimiser le code car les compilateurs modernes l'optimise facilement, d'une part. D'autre part, il est trés difficile de débugger une tel structure de programme si on s'amuse à l'optimiser soi-même. Dans ce code, la tabulation est considérée comme un espace.
L'intéret majeur d'un tel code, c'est qu'il est facilement implémentable dans tout compilateur C/C++ sans demandé de resource particulaire.

~ bigloo
Messages postés
1100
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
17 octobre 2012
7
Bonjour,



J'ai pas tout compris ce que tu dis mais je vois pas ce que tu reproche
à mon alocation dynaique ? et aussi tu as des compilateurs avec
presques pas de lignes toi !



C'est quoi ton compilo ?

J'ai pas trop compris l'histoire de la tabulation qui est présente dans mon code.



Merci,



Le créateur du site http://victorlogiciels.com
Messages postés
7
Date d'inscription
mercredi 5 octobre 2005
Statut
Membre
Dernière intervention
1 novembre 2007

Bonjour,

Mon compilo dépend du travail que je fais, en voici une liste cc (UNIX), gcc (UNIX), Dev-C++ (Win), FPC (Win), Lua (Prog Parralléle de typage C) et LeLisp. Je ne reproche rien à ton code, il fonctionne et en générale c'est ce qu'on demande à un code. Maintenant, il faut faire un automate et je maintient (Je suis un peu tête de turque).

Je n'ai rien à redire sur ton attribution de mémoire dynamique car moi-même j'en fais de manière déguisée. Quand on écrit char s[n]; c'est comme si on avait écrit char *s; c = (char *) malloc (sizeof(char) * (n + 1)); et c'est ce que fera le compilateur dans le code compilé.

Dans mon code, j'ai fait une erreur. La tabulation est représenté par \9 alors que j'aurais du la représenter par \t. Mais cela n'a pas d'importance à compilation. Lorsque l'on fait un appel à partir d'un batch, script shell ou d'un programme pour lancer un autre programme en lui passant des arguments, dans cette chaîne de caractère, il est nullement interdit de mettre une tabulation. Visuellement, une tabulation est représenté comme une suite d'espace entre deux groupe de caractères. Et, en général, dans le monde de la compilation (personne qui écrive des compilateurs), il est considéré comme un espace. Dans notre cas, il s'agit, donc, d'un séparateur d'argument au même titre que l'espace. Il en existe un autre qui est le retour chariot (je ne rentrerais pas dans le détaille).

Il faudrait le traiter dans ton code.

En relisant ton code, je me suis appercu que tu fais appel à plusieurs boucles. Dans un automate, tu utilises qu'une seule boucle. Je n'ai pas regardé le temps de calcul mais il est claire que si ta donnée à n caractères, ton temps de calcul est supérieure à 2 * n caractères (une fois pour lire le nombre d'argument, une fois pour extraire les arguments). Dans ma méthode, mon temps de calcul est égale à n caractères. Donc en claire, je mets deux fois moins de temps que toi pour réaliser la même chose (a peu près) car je ne délivre pas le nombre d'argument.

En résumer: Dans ma méthode, le compilateur doit coder une boucle et des branchements conditionnels. Dans ta méthode, le compilateur doit coder plusieurs boucles et des branchements conditionnels. Le résultat, c'est que le compilateur en voyant cela va utiliser une pile pour les appels de tes boucles, c'est à dire que il perdera plus de temps empiler et dépiler l'état des boucles qu'à réssoudre le problème.

Maintenant, je dit qu'il faut utiliser un automate et uniquement un automate car il y a des chercheurs en informatique, ayant travaillé sur le sujet, qui ont établi une méthode pour écrire un temps record de tel code. Cela ma pris environs 2min pour mettre sur le papier l'automate et 5min pour l'écrire en C. En moins de 10min, je connaissais, donc, le résultat. Un gain de temps appréciable quand on est en retard dans ces développements et surchargé de travail!

Par contre, je reconnais qu'il faut connaître deux outils mathématique et informatique pour appliquer la méthode:
- les automates de Turing
- les languages fonctionnelles
Ce qui n'est pas donnée à tout le monde. Tout bon livre de sur le sujet de la compilation les abordera car il sont incontournable si il ne l'ai aborde pas, le livre n'est qu'un bouquin permettant d'appliquer sans comprendre tous les mécanismes de mise en oeuvre de la compilation. En général, il traite que d'une seule méthode.

Je vais reviser mon code pour te fournir le nombre d'argument avec la liste des arguments et utiliser une attribution dynamique de la mémoire pour la chaîne de caractères.

~ bigloo
Messages postés
7
Date d'inscription
mercredi 5 octobre 2005
Statut
Membre
Dernière intervention
1 novembre 2007

Voici une correction de mon code, il copie la chaîne de caractères tel qu'il injecte des \0 au bonne place et note les adresses de début de chaque sous chaîne dans une structure de liste qui est réinjecté dans un tableau de pointeur de chaine et décompte le nombre de de sous chaîne en une passe.





en entrée:


- ligCommande est la variable de type LPSTR de la fonction WinMain


en sortie:


- nbArg: Nombre d'argument lu dans la ligne de commande


- Arg[i]: i-ème argument de la ligne de commande


typedef struct __lstAdr {
char *adr;
__lstAdr *next;
} lstAdr;
lstAdr *ptList, *aux;
ptList = NULL;
aux = NULL;

typedef char *string;

/* Lecture de la ligne de commande mis dans un tableau de chaîne */

char **Arg, *LstArg, c, *str;
int i, nbArg, etat;

etat = 0; // Initialisation de l'état de début de l'automate
i = 0; // Index de scrutation de la chaîne de caractères initialisé à 0
nbArg = 0; // Initialisation du nombre d'argument
// Initialisation de la chaîne de stockage
LstArg = (char *) malloc (sizeof(char) * (strlen(ligCommande) + 1));
LstArg[0] = '\0';

// AUTOMATE
while (etat != 2) { // Négation de la conditon de sortie

// Copie du caractère à l'index i dans la chaîne de stockage
c = ligCommande[i];
LstArg[i] = c;

switch (etat) {

case 0: // Etat initiale
switch (c) {
case ' ': case '\t': break;
case '"': etat = 3; break;
case '\0': etat = 2; break;
default:
aux = (__lstAdr *) malloc (sizeof(char) + 1);
aux->adr = &(LstArg[i]);
aux->next = ptList;
ptList = aux;
etat = 1;
}
break;

case 1: // Reconnaissance d'une chaîne entre espace if ((c ' ') || (c '\t') || (c == '\0')) {
nbArg++;
LstArg[i] = '\0'; if (c '\0') etat 2;
else etat = 0;
}
break;

case 2: break; // Etat Terminal (On ne fait rien, c'est juste pour le marquer

case 3: // Reconnaissance d'une chaîne entre double quote if (c '\0') etat 2;
else {
aux = (__lstAdr *) malloc (sizeof(double) + 1);
aux->adr = &(LstArg[i]);
aux->next = ptList;
ptList = aux;
etat = 5; if (c '"') etat 4;
}
break;






case 4: // Fin de lecture d'une chaîne double quote
etat = 5; if ((c ' ') || (c '\t') || (c == '\0')) {
nbArg++;
LstArg[i-1] = '\0';
etat = 0; if (c '\0') etat 2;
}
break;

case 5: // Chaîne entre double quote avec au moins 1 caractères
switch (c) {
case '"': etat = 4; break;
case '\0': nbArg++; etat = 2; break;
}
break;
}
i++;
}

// Mise en place dans un tableau a deux dymensions des chaînes trouvées
Arg = (char **) malloc (sizeof(char *) * (nbArg + 1));
for (i = nbArg; i > 0; i--) {
Arg[i - 1] = ptList->adr;
aux = ptList;
ptList = ptList->next;
aux->next = NULL
free (aux);
}
Arg[nbArg] = NULL;


~ bigloo
Messages postés
1100
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
17 octobre 2012
7
Bonjour,



Je n'ai pas dit que mon code était optimisé mais qu'il est court.

Je n'arrive pas beaucoup à m'auto-optimiser donc si tu peux me donner quelques astuces ça m'interesse !



Merci,



Le créateur du site http://victorlogiciels.com
Messages postés
7
Date d'inscription
mercredi 5 octobre 2005
Statut
Membre
Dernière intervention
1 novembre 2007

Bonsoir,

Il ne faut pas avoir d'idée préconsu sur la rapidité d'un programme, un programme court n'est pas forcément rapide. Un programme long non plus. Ce n'est pas au nombre de ligne que l'on juge la rapidité d'un programme. Cela se calcul dans certain cas ou se test dans d'autre. Par exemple, si je code cette lecture pour du lua comme c'est de la programmation parallèle, par cas cela va me prendre 1 ligne, soit en 5 lignes, j'ai résolue mon problème de la longueur du programme, géniale!! Et bien non si je code la même chose en listp, cela se code en 1 ligne. J'ai fait mieux ? et bien non. Dans les deux cas, on oubli qu'il y a dérrière un compilateur et un interpréteur qui arrange le coût. Et si on regarde de plus prés le code, on a de forte chance de s'appercevoir qu'ils sont de la même complexité. C'est un mot barbare, mais de nombreux livres en parle.

Comment cela marche:

Dans un premier temps, il faut écrire un algo sur papier reprenant les principales oppérations voulues sur une structure de données et déterminer le nombre de fois que l'on sera obligé de faire une opération élémentaire sur cette structure. La valeur s'exprime en fonction du nombre d'élément dans la structure. En général, on parle en T(x), avec x pouvant prend comme valeur ln(n), en, n, a * n, n2 et nn, ou a est une constante et n le nombre de données dans la structure. Cela est la théorie.

Tu sais bien que l'on peut créer plusieurs structures différentes pour contenir le même type de donnée. Par exemple: pour une liste triée, on peut utiliser un tableau, des arbres binaires, des arbres n-aires et des structures avec indexation par archage. Ce qui est amusant avec cette exemple, c'est en fonction du nombre de données à traiter, il faudra choisir plus une structure qu'une autre. Par chance, il existe plien d'ouvrage sur le sujet qui donne directement la solution:

- moins de 10 éléments, structure tableau avec une ittération simple
- au moins 100 éléments, structure tableau avec une ittération logarithmique
- jusqu'à 2000 élément, structure d'arbre binaire avec une ittération logarithmique
- au delà, structures avec indexation par archage avec une clé oracle

Revenons au problème posé, il s'agit de ligne une chaîne de caractère et d'en extraire les éléments. Bien recherchons les méthodes connues qu'il font déjà cela. Eeuu ... un compilateur. L'une des tâches du compilateur est de lire un fichier source (notre chaîne de caractères), reconnaître les éléments (Typage), vérifier leur ordonnancement (Régle de grammaire pour l'écriture d'un programme), vérifier intégriter des données (Cohérence des types), coder en un language exécutable (Assemblage) et mettre sous forme normale (Régle d'optimisation). Voila ce que fait un compilateur. Le typage est de reconnaître des mots dans le fichier, les ouvrages sur le sujet parle d'automate et termine sur l'utilisation de l'outil LEXX. LEXX est un programme qui prend un ensemble de syntaxe et rend l'automate qui comprend cette ensemble de syntaxe en C, pascal, fortran, etc... (il suffit de lui donner le language cible). Pour notre exemple, on aurait l'ensemble suivant:
- \b\t
- [^"].*[\b\t$]
- ".*"[\b\t$]
Je ne te demande pas de comprend la syntaxe de définition de l'ensemble de syntaxe car il manque la partie exploitation, ou on dit qu'il faut pas prendre en compte les " et \b en début ou en fin, ce n'est pas le but. Les chercheurs ont choisi l'automate pour deux raisons simples:
- d'un état et d'une donnée, il dertermine un nouvel état connu
- il termine toujours (quoi que)
En fait, la deuxième raison n'est pas totalement vrai et est uniquement vrai si on utilise la méthode d'écrit par les chercheurs qui garantie la terminaison de l'automate. On est, donc, capable d'écrire un programme pouvant lire une chaîne de caractères et garantir la terminaison.

Maintenant, un peu d'histoire.

Un type génial a écrit un compilateur qui effectué une lecture du fichier par récurrence. Donc pour écrire son programme, il avais réduit à deux fonctions récursives qui s'appelaient mutuellement. Fort de sa découverte d'un code court permettant de faire de la compilation, il le présente à la communoté des chercheurs en informatique (ce sont plus des mathématicien), et voila, qu'un obcure étudiant japonné en mathématique fondamental mais en défaut son code (Je me souviens plus de son nom mais il a donnée son nom à un algo). Cette première histoire, permet de savoir qu'il faut fuir les fonctions récurssives pour résoudre le problème ce que tu as fait.

Une autre histoire qui est toujours d'actualiter, un suisse avec le concours d'autre personne a écrit un compilateur libre de source pour que ces étudiants puis apprendre la programmation (je parle du language Pascal). La particularité à l'époque de ce compilateur, il compile en une seule passe. C'est à dire qu'il lie une seule fois chaque caractère du fichier source et rend le fichier compilé. Cette second histore, permet de savoir qu'il est possible de lire une unique fois un fichier source pour en extraite les mots du language.

Il reste plus qu'à trouver la bonne structure permettant la lecture en une fois de la chaine de caractères par un automate. Voici l'automate que j'ai mis sur le papier:

eol: représente la fin de la chaîne de caractère
#32: représente la caractère espace
#9: représente le caractère tabulation
@ : action de récupération de l'adresse du caractère lue
+ : action d'incrémentation du nombre d'argument

Maintenant reprenons ton code, tout n'est pas à jeter, l'attribution de mémoire par double pointeur est une excellente idée. Et deux lignes plus bas, façon de parler, tu nous alloue une espace certe suffisant mais bon pourquoi autant de caractères. Cela je peux le comprendre lorsque l'on travail sous UNIX, Linux qui est la taille en standard de la ligne de commande. Si je passe sous Windows, il s'agit de 256. Quoi que, il me semble que l'on peut modifier cette taille et mettre ce que l'on veut du moment qu'il s'agit d'un multi de 128. Imagine, un responsable réseau, pour une obcure raison a décidé d'avoir une autre définition de la taille maximum de la ligne de commande. Ex: il doit taper une commande oracle trés trés longue. Ton code ne marche plus. Mais on garde l'idée du double pointeur et on l'utilise comme un tableau de taille dynamique de pointeur de caractère. Maintenant, tu copie la chaîne de la ligne de commande dans des sous chaînes, l'idée est gardé car cela évite de modifier la ligne de commande en mémoire de la machine (éviter de modifier les données externe) mais sous une autre forme on effectue une copie intelligente. En C, la fin d'un d'une chaîne de caractère est \0, cela tu l'as bien fait, d'où l'idée suivante, on utilise \0 pour effacer les caractères sentinels de la chaîne lue. A chaque fois que l'on ne peut plus effacer, on concerve l'adresse dans le tableau dynamique de pointeur de caractère. A chaque fois que l'on peut a nouveau effacer ou que l'on a attiend la fin de la chaîne, on incrémente le nombre d'argument lue. Comme représenter sur le schémas suivant:



Voici mon code final compilable sous Dev-C++ pour le problème posé:

Avant de le compiler, mettre ces paramétres:
Dans option projet > Paramétres > Compilateur: -Wall
Dans option projet > Paramétres > Editeur de liens: -mWindows

#include





/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);





/* Make the class name into a global variable */
char szClassName[ ] = "Win32";
WNDPROC OldEditProc;





/* Définition d'une structure de liste d'argument */
typedef struct __LstArg {
int nbArg;
char **Arg;
char *memoire;
} LstArg;





LRESULT CALLBACK EditProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam) {
// Ignorer les touches du clavier si lecture seule: if ((uMsg WM_KEYDOWN) && (wParam VK_DELETE)) return 0;
if ((uMsg == WM_CHAR) && (wParam != VK_RETURN) && (wParam != VK_ESCAPE)) return 0;
// Empêcher selection si bouton gauche appuyé avec déplacement de la souris: if ((uMsg WM_MOUSEMOVE) && (wParam MK_LBUTTON)) return 0;
// Ignorer double clic et EM_SETSEL si non sélectionnable: if ((uMsg WM_LBUTTONDBLCLK) || (uMsg EM_SETSEL)) return 0;
// Ignorer clic droit si Menu contextuel désactivé:
if (uMsg == WM_RBUTTONDOWN) return 0;
// Empecher couper, coller, annuler ou supprimer en lecture seule: if ((uMsg WM_PASTE) || (uMsg WM_CUT) || (uMsg == WM_UNDO) || (uMsg == WM_CLEAR)) return 0;
// Appeler la procédure originale:
return CallWindowProc(OldEditProc, hWnd, uMsg, wParam, lParam);
}





void LectureArgument (LstArg *SArg, LPSTR msg) {
/* Lecture de la ligne de commande mis dans un tableau de chaîne */

char c;
int i, etat;

etat = 0; // Initialisation de l'état de début de l'automate
i = 0; // Index de scrutation de la chaîne de caractères initialisé à 0

/* Initialisation de la variable de retour */

// Initialisation de la chaîne de stockage
SArg->memoire = (char *) malloc (sizeof(char) * (strlen(msg) + 1));
SArg->memoire[0] = '\0';

// Initialisation de la table des arguments
SArg->Arg = (char **) malloc (sizeof(char *) * 1);
SArg->Arg = NULL;

// Initialisation du nombre d'argument lue
SArg->nbArg = 0;

// AUTOMATE
while (etat != 2) { // Négation de la conditon de sortie

// Copie du caractère à l'index i dans la chaîne de stockage
c = msg[i];
SArg->memoire[i] = c;

switch (etat) {

case 0: // Etat initiale
switch (c) {
case ' ': case '\t': break;
case '"': etat = 3; break;
case '\0': etat = 2; break;
default:
SArg->Arg = (char **) realloc (SArg->Arg, sizeof(char *) * (SArg->nbArg + 1));
SArg->Arg[SArg->nbArg] = &(SArg->memoire[i]);
etat = 1;
}
break;

case 1: // Reconnaissance d'une chaîne entre espace if ((c ' ') || (c '\t') || (c == '\0')) {
SArg->nbArg++;
SArg->memoire[i] = '\0'; if (c '\0') etat 2;
else etat = 0;
}
break;

case 2: break; // Etat Terminal (On ne fait rien, c'est juste pour le marquer

case 3: // Reconnaissance d'une chaîne entre double quote if (c '\0') etat 2;
else {
SArg->Arg = (char **) realloc (SArg->Arg, sizeof(char *) * (SArg->nbArg + 1));
SArg->Arg[SArg->nbArg] = &(SArg->memoire[i]);
etat = 5; if (c '"') etat 4;
}
break;





case 4: // Fin de lecture d'une chaîne double quote
etat = 5; if ((c ' ') || (c '\t') || (c == '\0')) {
SArg->nbArg++;
SArg->memoire[i-1] = '\0';
etat = 0; if (c '\0') etat 2;
}
break;

case 5: // Chaîne entre double quote avec au moins 1 caractères
switch (c) {
case '"': etat = 4; break;
case '\0': SArg->nbArg++; etat = 2; break;
}
break;
}
i++;
}
}





int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR ligCommande ,
int nFunsterStil)





{
// Déclaration de l'unite de visualisation des informations lues

HWND hEdit;
LstArg *hArg;
int i;

LectureArgument (hArg, ligCommande);

HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */





/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);





/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default color as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;





/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;





/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Lecture des arguments passés à l'exe en Win32", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
430, /* The programs width */
105, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);


/* Make the window visible on the screen */
ShowWindow (hwnd, nFunsterStil);

// Création d'un fenêtre de visualisation des arguments retenues
CreateWindow ("STATIC", "Liste des argument",
WS_CHILD | WS_VISIBLE,
10, 10, 400, 18,
hwnd, 0, hThisInstance, NULL);
hEdit = CreateWindow ("COMBOBOX", "",
WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | CBS_AUTOHSCROLL | CBS_DROPDOWN,
10, 34, 400, 200,
hwnd, NULL, hThisInstance, NULL);
OldEditProc = (WNDPROC) SetWindowLong (GetWindow (hEdit, GW_CHILD), GWL_WNDPROC, (LPARAM) EditProc);
for (i = 0; i < hArg->nbArg; i++) {
SendMessage(hEdit, CB_INSERTSTRING, (WPARAM) -1, (LPARAM) hArg->Arg[i]);
}
SendMessage (hEdit, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);

/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}





/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}





/* This function is called by the Windows function DispatchMessage() */





LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}





return 0;
}

~ bigloo