Versione documento: 1.2 — luglio 2025
Questo documento descrive in dettaglio l'architettura, le scelte progettuali e l'uso del Sistema Gestione Spedizioni sviluppato in linguaggio C. È pensato per i membri del team di sviluppo: vuole essere allo stesso tempo tecnico e facile da consultare.
- Funzioni complete documentate: aggiunta sezione dettagliata con tutte le funzioni disponibili nel sistema, organizzate per modulo
- Algoritmo Bin Packing: aggiunta la funzione di pianificazione del caricamento dei camion usando l'algoritmo Worst-Fit
- Validazioni avanzate: migliorate le funzioni di validazione con controlli più rigorosi
- Gestione memoria ottimizzata: migliorata la gestione dell'ownership e della memoria
- 1. Obiettivi del progetto
- 2. Struttura delle directory
- 3. Principi di progettazione adottati
- 4. Panoramica dei moduli
- 5. Funzioni complete del sistema
- 6. Flusso di esecuzione (runtime)
- 7. Scelte implementative chiave
- 8. Compilazione e sviluppo
- 9. Linee guida di codifica
- 10. Roadmap e miglioramenti futuri
- 11. Contatti
- Gestire l'intero ciclo di vita di una spedizione (creazione, modifica, ricerca, cancellazione, salvataggio/caricamento da file, ordinamento, pianificazione carico).
- Garantire affidabilità tramite validazione degli input e programmazione difensiva.
- Mantenere manutenibilità con una struttura modulare e uso di ADT (Abstract Data Type).
- Offrire un'interfaccia CLI cross-platform (Windows / Unix) completamente in standard C99, senza dipendenze esterne.
ProgettoLaboratorio/
├── Headers/ # Header pubblici dei moduli
├── Source/ # Implementazioni (.c)
├── bin/ # Eseguibili generati dal Makefile/Code::Blocks
├── obj/ # File oggetto intermedi
├── dati.txt # File CSV di esempio per il caricamento
└── README.md # Questo documento
- Separazione delle responsabilità: chi include un header ottiene solo l'API pubblica, mentre l'implementazione resta nascosta.
- Facilità di compilazione: il
Makefilee il progetto Code::Blocks aggiungono entrambe le cartelle alinclude path, evitando prefix lunghi nei#include.
| Principio | Applicazione nel codice |
|---|---|
| Modularità | Ogni concetto (Persona, Spedizione, Lista, I/O, Validazione…) ha un modulo dedicato. |
| ADT & Information Hiding | Strutture definite come puntatori opachi (typedef struct X *X) nei .h; i campi reali sono nel .c. |
| Programmazione difensiva | Il modulo validate centralizza tutte le verifiche (stringhe, date, pesi, CAP, ecc.). |
| Responsabilità chiara | Ogni funzione fa una cosa e la documentazione Doxygen spiega pre/post-condizioni. |
| Error Handling esplicito | Le funzioni restituiscono bool / int per indicare successo/fallimento; l'UI (io_utils) mostra l'errore all'utente. |
| Portabilità | Solo librerie standard C; uso di ClearScreen() che rileva il sistema operativo a runtime. |
| Modulo | Scopo principale | Dettagli notevoli |
|---|---|---|
io_utils |
Gestione input/output dell'utente | Funzioni di prompt con validazione immediata; lunghezze costanti centralizzate. |
person |
ADT Person (mittente/destinatario) |
Setter/Getters safe-string, responsabilità di ownership ben documentata. |
shipment |
ADT Shipment |
Enum ParcelType, multi-level printing (PrintShipment vs PrintShipmentTable). |
list |
Lista semplicemente concatenata di Shipment |
Inserimento in testa, ricerca per codice, serializzazione CSV, ordinamento tramite MergeSort. |
validate |
Programmazione difensiva | Funzioni IsValidXYZ riusate da tutti gli altri moduli. |
operation |
Layer "business logic" | Incapsula le operazioni del menu, mantiene UI separata dal model. |
main |
Punto di ingresso | Loop menu, delega tutta la logica ai moduli precedenti, gestione ciclo di vita della lista. |
shipment_cmp |
Funzioni di confronto | Comparatori multipli per l'ordinamento delle spedizioni. |
- Il chiamante che crea un oggetto (es.
CreatePerson) ne cede l'ownership ai contenitori (Shipment,List). - Le funzioni
Destroy*propagano la distruzione (es.DestroyShipmentdistrugge anche sender/recipient). - Questo pattern evita leak e facilita il riuso delle strutture.
ReadString(const char *prompt, char *buffer, int size)- Legge una stringa da stdinReadInt(const char *prompt, int *out)- Legge un intero da stdinReadFloat(const char *prompt, float *out)- Legge un numero in virgola mobileReadDate(const char *prompt, struct tm *out)- Legge una data (giorno, mese, anno)ReadType(ParcelType *out)- Legge il tipo di paccoReadPerson(const char *ruolo, Person *out)- Legge tutti i campi di una personaReadArrivalDate(const char *prompt, struct tm *arrival, struct tm departure)- Legge data di arrivo ≥ partenza
PrintMenu()- Stampa il menu principale del programmaPrintMessage(const char *msg)- Stampa un messaggio genericoPrintSectionHeader(const char *title)- Stampa un'intestazione di sezioneClearScreen()- Pulisce lo schermo in modo portabileWaitEnter()- Pausa l'esecuzione finché l'utente non preme invio
CreatePerson(const char *name, const char *surname, const char *address, const char *city, const char *cap, const char *phone)- Crea un nuovo oggetto PersonDestroyPerson(Person p)- Dealloca un oggetto Person
GetName(Person p)/SetName(Person p, const char *name)- NomeGetSurname(Person p)/SetSurname(Person p, const char *surname)- CognomeGetAddress(Person p)/SetAddress(Person p, const char *address)- IndirizzoGetCity(Person p)/SetCity(Person p, const char *city)- CittàGetCap(Person p)/SetCap(Person p, const char *cap)- CAPGetPhone(Person p)/SetPhone(Person p, const char *phone)- Telefono
PrintPerson(Person p, FILE *out)- Stampa una persona su uno stream
CreateShipment(const char *code, ParcelType type, float weight, struct tm departure, struct tm arrival, Person sender, Person recipient)- Crea una nuova spedizioneDestroyShipment(Shipment s)- Dealloca una spedizione e le persone collegate
GenerateShipmentCode(char *code_out, const char *prefix)- Genera un nuovo codice spedizione unico
GetCode(Shipment s)/SetCode(Shipment s, const char *code)- Codice spedizioneGetType(Shipment s)/SetType(Shipment s, ParcelType type)- Tipo di paccoGetWeight(Shipment s)/SetWeight(Shipment s, float weight)- PesoGetDepartureDate(Shipment s)/SetDepartureDate(Shipment s, struct tm departure)- Data partenzaGetArrivalDate(Shipment s)/SetArrivalDate(Shipment s, struct tm arrival)- Data arrivoGetSender(Shipment s)/SetSender(Shipment s, Person sender)- MittenteGetRecipient(Shipment s)/SetRecipient(Shipment s, Person recipient)- Destinatario
PrintShipment(Shipment s, FILE *out)- Stampa dettagli completi della spedizionePrintShipmentTable(Shipment s, FILE *out)- Stampa la spedizione in formato tabellareParcelTypeToString(ParcelType t)- Converte un ParcelType in stringa leggibile
CreateList()- Crea una lista vuota di spedizioniDestroyList(List l)- Dealloca completamente la lista e tutte le spedizioni
InsertShipment(List l, Shipment s)- Inserisce una nuova spedizione in testaDeleteShipment(List l, const char *code)- Rimuove la spedizione con il codice specificatoFindShipment(List l, const char *code)- Ricerca una spedizione per codice
PrintList(List l, FILE *out)- Stampa tutte le spedizioni con dettagli completiPrintListTable(List l, FILE *out)- Stampa le spedizioni in formato tabellare
SaveListToFile(List l, const char *filename)- Salva l'intera lista su file CSVLoadListFromFile(const char *filename)- Carica una lista da file
SortList(List l, int (*cmp)(Shipment, Shipment))- Ordina la lista con MergeSortIsListEmpty(List l)- Verifica se la lista è vuotaCountShipments(List l)- Conta le spedizioni nella listaForEachShipment(List l, void (*callback)(Shipment))- Esegue una callback per ogni spedizioneGenerateShipmentCodeWithList(List l, char *code_out, const char *prefix)- Genera codice unico usando la lista
IsValidCap(const char *cap)- Verifica la validità di un CAP italianoIsValidPhone(const char *telefono)- Verifica la validità di un numero di telefonoIsValidName(const char *nome)- Controlla se un nome è validoIsValidSurname(const char *cognome)- Controlla se un cognome è validoIsValidCode(const char *codice)- Verifica se un codice spedizione rispetta il formatoIsValidCity(const char *citta)- Controlla la correttezza di una città
IsValidWeight(float peso)- Valida il peso del pacco
IsValidDate(struct tm data)- Controlla la correttezza di una dataIsDepartureBeforeOrEqualArrival(struct tm departure, struct tm arrival)- Verifica che partenza ≤ arrivo
IsValidPerson(Person p)- Esegue controlli di consistenza su un oggetto PersonIsValidShipment(Shipment s)- Esegue controlli di consistenza su un oggetto ShipmentIsDelivered(Shipment s)- Verifica se una spedizione è già stata consegnata
InsertShipmentOperation(List lista)- Inserisce una nuova spedizioneEditShipmentOperation(List lista)- Modifica una spedizione esistenteDeleteShipmentOperation(List lista)- Elimina una spedizione
SearchShipmentOperation(List lista)- Cerca una spedizione per codiceViewAllShipmentsOperation(List lista)- Visualizza tutte le spedizioni
SortShipmentsOperation(List lista)- Ordina le spedizioni secondo diversi criteri
SaveToFileOperation(List lista)- Salva la lista su fileLoadFromFileOperation(List *lista)- Carica la lista da file
BinPackingOperation(List lista)- Pianifica il caricamento dei camion con Worst-Fit
CompareShipmentByCode(Shipment a, Shipment b)- Per codice (alfabetico)CompareShipmentByWeight(Shipment a, Shipment b)- Per peso (crescente)CompareShipmentByWeightDesc(Shipment a, Shipment b)- Per peso (decrescente)CompareShipmentByType(Shipment a, Shipment b)- Per tipo di paccoCompareShipmentByDepartureDate(Shipment a, Shipment b)- Per data partenzaCompareShipmentByArrivalDate(Shipment a, Shipment b)- Per data arrivoCompareShipmentBySenderName(Shipment a, Shipment b)- Per nome mittenteCompareShipmentByRecipientName(Shipment a, Shipment b)- Per nome destinatarioCompareShipmentBySenderCity(Shipment a, Shipment b)- Per città mittenteCompareShipmentByRecipientCity(Shipment a, Shipment b)- Per città destinatario
flowchart TD
Start([Avvio programma]) --> Init[List = CreateList()]
Init --> Menu{PrintMenu() \n e scelta utente}
Menu -->|1| Op1[InsertShipmentOperation]
Menu -->|2| Op2[EditShipmentOperation]
Menu -->|3| Op3[SearchShipmentOperation]
Menu -->|4| Op4[ViewAllShipmentsOperation]
Menu -->|5| Op5[SortShipmentsOperation]
Menu -->|6| Op6[DeleteShipmentOperation]
Menu -->|7| Op7[SaveToFileOperation]
Menu -->|8| Op8[LoadFromFileOperation]
Menu -->|9| Op9[BinPackingOperation]
Menu -->|0| End[DestroyList & Exit]
subgraph Persistenza
Op7 --> File[(CSV File)]
Op8 -->|sostituisce lista| List
end
Nota: la scelta del formato CSV semplifica l'import/export e consente apertura rapida in Excel o LibreOffice.
- Ordinamento MergeSort → la lista delle spedizioni può essere ordinata secondo criteri multipli selezionabili dall'utente, grazie a comparatori modulari e all'algoritmo MergeSort su lista collegata.
- Algoritmo Bin Packing → pianificazione ottimale del caricamento dei camion usando l'algoritmo Worst-Fit per massimizzare l'utilizzo dello spazio.
- Enum
ParcelType→ leggibile (LETTERA,PICCOLO, …) + conversioneParcelTypeToStringper l'output. - Codice spedizione univoco → funzione
GenerateShipmentCodeispeziona la lista e aggiunge un progressivo a sei cifre al prefisso. - Serializzazione/Deserializzazione → tutte le funzioni I/O sono in
list.cper tenere lontano il parsing dalla UI. - Standard C99 → miglior
for-declaratione funzioni<stdbool.h>senza rinunciare alla portabilità. - Doxygen → ogni modulo include tag
@file,@brief, parametri,@return; si può generare la documentazione HTML con:doxygen Doxyfile
# Compilazione debug
make
# Pulizia
make cleanIl target predefinito compila con -Wall -Wextra -g -std=c99.
- Progetto aggiornato in
ProgettoLaboratorio.cbp. - Due build targets: Debug (con
-g) e Release (con-O2 -s).
- Compilatore:
gcc≥ 9 oclang≥ 11. - Analisi statica:
clang-tidy,cppcheck. - Test Valgrind:
valgrind --leak-check=full ./bin/programma.exe.
- Snake_case per funzioni (
create_personsarebbe C-like, qui usiamoCreatePerson). - Costanti
ALL_CAPSe suffisso_LENper lunghezze. - Commenti Doxygen in italiano brevi ma completi.
- Ogni modulo esporta solo il necessario; le funzioni
staticrestano nel.c.
- Unit test con Unity o CMock (i test legacy sono stati rimossi nella refactor ma vanno ripristinati).
- Log su file con livelli (INFO/WARN/ERROR) per audit.
- Interfaccia grafica (GTK/Qt) mantenendo intatta la business logic.
- Internationalization (i18n): separare stringhe UI in file risorsa.
- Algoritmi di ottimizzazione avanzati per il bin packing (First-Fit Decreasing, Best-Fit).
| Ruolo | Nome | |
|---|---|---|
| Maintainer | Flavio De Musso | flavio@example.com |
| Developer | Giuseppe Di Cosola | giuseppe@example.com |
| Developer | Gabriele Farigu | gabriele@example.com |
Buon hacking!