Visualizzazione dei risultati da 1 a 4 su 4
  1. #1
    Utente di HTML.it
    Registrato dal
    Jul 2001
    Messaggi
    1,003

    [C] Gestire menu e sottomenu

    Salve.
    Sto facendo una specie di shell sulla seriale, il particolare di questa shell è che non è ammissibile che ci siano tempi di wait.
    Ovvero, non è possibile usare la scanf (perchè si mette in attesa del prossimo carattere).
    Il codice l'ho gia fatto e funziona ottimamente, però cerco qualche consiglio per migliorarlo nella sua struttura.
    Non badate tanto a come son dichiarati gli array (ed eventuali bufferoverflow) o alle routine di gestione della seriale (in realtà non sono quelle, visto che uso un microcontrollore, so che la getch() si mette in attesa, non badateci), ma piuttosto nella forma del programma, sulla sua elasticità a inserire nuovi comandi e menu.
    In pratica ora come ora ogni comando è dichiarato come funzione e uso un puntatore a funzione (che si chiama "function") per gestire qual'è la prossima funzione da eseguire.
    Per "comando" si intende una stringa terminata dalla pressione del tasto INVIO.
    Naturalmente i comandi che vedete sono di puro esempio. echo fa l'eco della stringa passata come primo parametro, add fa la somma del 2 e terzo parametro.
    Qualche altro miglioramento possibile?
    Grazie.

    codice:
    #include <stdio.h>
    #include <stdlib.h>
    
    #define PASSWORD "test"
    
    static char buffer[100];
    static int chused;
    static void (*function) (char * command); 
    
    
    int loop (void);
    void prompt (void);
    void motd (char * command);
    void askpassword (char * command);
    void checkpassword (char * command);
    void mainmenu (char * command);
    void printmainmenu (void);
    void echocommand (char * command);
    void mathmenu (char * command);
    void printmathmenu (void);
    void addition (char * command);
    char readserial (void);
    void clearbuffer (void);
    
    
    
    int main(int argc, char *argv[])
    {
        
      function= motd;
        
      for (;;)
          loop();
        
      system("PAUSE");	
      return 0;
    }
     
    
    int loop (void)
    {
      if (readserial() == 13) // è stato premuto INVIO, elabora comando
      {
        buffer[--chused] = 0; // elimino il tasto INVIO
        function (buffer);
        prompt ();
        clearbuffer ();
      }
      
    }
    
    void motd (char * command)
    {
         printf ("Interfaccia SERIAL/0 pronta. Premere INVIO per autenticarsi\n");
         function = askpassword;
    }   
      
    void askpassword (char * command)
    {
         printf ("Inserire la password: ");
         function= checkpassword;
    }    
    
    void checkpassword (char * command)
    {
    
         if (strcmp(command, PASSWORD) == 0)
         {
             printf ("PWD ok \n");
             function = mainmenu;
             printmainmenu();
         }
         else
         {
             printf ("PWD errata\n");
             askpassword(command);
         }
    }
        
    void prompt (void)
    {
         if (function == mainmenu)
            printf ("main>");
         if (function == mathmenu)
            printf ("main>math>");
    }
    
    
    void mainmenu (char * command)
    {
         char s1 [100];
         
         sscanf (command, "%s", s1);
     
         if (strcmp(s1, "?") == 0)
            printmainmenu ();       
         else if (strcmp(s1, "echo") == 0)
            echocommand (command);
         else if (strcmp (s1, "math") == 0)
            {
               printmathmenu();
               function = mathmenu;
    
            }
         else if (strcmp (s1, "quit") == 0)
            exit (0);
         else   
            printf ("Comando non valido \n");
         
    
         
    }
    
    void printmainmenu (void)
    {
         printf ("--- MAIN MENU ---\n Comandi supportati:\n?\necho\nmath\nquit\n");
    
    }
    
    void echocommand (char * command)
    {
         char s1 [100];
         char s2 [100];
         
         sscanf (command, "%s %s", s1, s2);
         printf ("%s \n", s2);
    }
    
    void mathmenu (char * command)
    {
         char s1 [100];
         
         sscanf (command, "%s", s1);
         
         if (strcmp(s1, "?") == 0)
            printmathmenu ();
         else if (strcmp(s1, "add") == 0)
            addition (command);
         else if (strcmp (s1, "back") == 0)
            {
                    function= mainmenu;
            }
         else
            printf ("Comando non valido \n");
         
    
         
    }
    
    void printmathmenu (void)
    {
         printf ("--- MATH MENU ---\n Comandi supportati:\n?\nadd\nback\n");
    
    }
    
    void addition (char * command)
    {
         char s1 [100], s2 [100] , s3 [100];
         int a, b;
         
         sscanf (command, "%s %s %s", s1, s2, s3);
         a = atoi (s2);
         b = atoi (s3);
         printf ("%s + %s = %d \n", s2, s3, a+b);
    }
    
         
         
    
    
    // ROUTINE GESTIONE SERIALE //
    
    
    char readserial (void)
    {
     char c = getch();
         if (c != 8)
            {
             buffer[chused++]= c;
             printf( "%c", c);
             }
         if (c==13)
           printf ("%c", 10); // new-line
         if (c==8) //backspace
         {
            printf( "%c", c); 
            printf ( "%c", 32);   
            printf ("%c", 8);   
            buffer[--chused]=0;
         }
     return c;
    }
            
    void clearbuffer (void)
    {
          int i;
         chused = 0;
         for (i=0; i<100; i++) buffer[i] = 0;
    }

  2. #2
    Utente di HTML.it
    Registrato dal
    Jul 2001
    Messaggi
    1,003
    Va gia bene cosi o è troppo incasinato il codice e per questo nessuno risponde?

  3. #3
    Originariamente inviato da tia86
    Va gia bene cosi o è troppo incasinato il codice e per questo nessuno risponde?
    Ciao

    sinceramente io, da lettore e potenziale modificatore del codice, non lo trovo molto chiaro se non altro per l'uso della tua "function". Lo trovo un metodo magari da utenti PRO ma davvero poco chiaro. Mi spiego meglio: il flusso di esecuzione è "criptato" in questo modo cioè è difficile vedere l'ordine logico in cui chiami le funzioni (da A a B a C ecc ecc). Io per semplicità e quindi per una futura e chiara manutenzione del codice non userei quella tecnica ma semplicimente le invocherei in sequenza. Si il main sarà poco più lungo ma non eccessivamente.

    In più dividerei il codice su più file. Almeno le routine per la seriale con il resto del programma.

    Ciao

  4. #4
    Utente di HTML.it
    Registrato dal
    Jul 2001
    Messaggi
    1,003
    Purtroppo non posso invocarle in sequenza.
    Mi spiego, prendo ad esempio la gestione dell'autenticazione.
    Normalmente si farebbe cosi:
    codice:
    do
    {
        printf("Inserisci la password: ");
    } while (lapasswordnonècorretta());
    Io una cosa del genere non posso farla, perchè sono su un microcontrollore, cioè lavoro senza sistema operativo, e con un codice del genere non posso far fare al micro nient'altro che controllare la seriale.
    Quello che posso fare è richiamare, ogni tanto, la funzione loop() e fargli fare un ciclo.
    A parte questa soluzione, l'unica che mi è venuta in mente è mettere una variabile di stato e ad ogni valore della variabile associare una funzione, ma alla fine è un altro modo di fare quello che ho fatto con un puntatore a funzione (che posso vederlo come una variabile di stato).
    In poche parole, è un automa a stati finiti.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.