Compare commits
4
Commits
0.2.0
..
fa0e377811
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa0e377811 | ||
|
|
defa951e51 | ||
|
|
c088caf03e | ||
|
|
8cd79da5eb |
No files matched your search
@@ -3,15 +3,66 @@
|
|||||||
|
|
||||||
#include <json-c/json.h>
|
#include <json-c/json.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Verifica se un file esiste sul disco.
|
||||||
|
* @param fname Percorso del file da controllare.
|
||||||
|
* @return 1 se il file esiste ed è accessibile, 0 altrimenti.
|
||||||
|
*/
|
||||||
int existsFile(const char *fname);
|
int existsFile(const char *fname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crea un nuovo file JSON inizializzandolo con un array vuoto ([]).
|
||||||
|
* @param fname Percorso del file da creare.
|
||||||
|
* @return 0 in caso di successo, -1 in caso di errore.
|
||||||
|
*/
|
||||||
int createFile(const char *fname);
|
int createFile(const char *fname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Rinomina o sposta un file esistente.
|
||||||
|
* @param oldName Vecchio percorso/nome del file.
|
||||||
|
* @param newName Nuovo percorso/nome del file.
|
||||||
|
* @return 0 in caso di successo, -1 in caso di errore.
|
||||||
|
*/
|
||||||
int renameDataFile(const char *oldName, const char *newName);
|
int renameDataFile(const char *oldName, const char *newName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Carica un array JSON da file. Se il file non esiste, lo crea automaticamente.
|
||||||
|
* @param fname Percorso del file JSON.
|
||||||
|
* @return Puntatore all'oggetto JSON (array) caricato, oppure NULL in caso di errore.
|
||||||
|
*/
|
||||||
json_object *loadJsonArray(const char *fname);
|
json_object *loadJsonArray(const char *fname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Salva un array JSON su file formattandolo in modo leggibile (indentato).
|
||||||
|
* @param fname Percorso del file di destinazione.
|
||||||
|
* @param arr L'oggetto JSON (array) da salvare.
|
||||||
|
* @return 0 in caso di successo, -1 in caso di errore.
|
||||||
|
*/
|
||||||
int saveJsonArray(const char *fname, json_object *arr);
|
int saveJsonArray(const char *fname, json_object *arr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cerca un oggetto all'interno di un array JSON basandosi sul campo "name".
|
||||||
|
* @param arr L'array JSON in cui effettuare la ricerca.
|
||||||
|
* @param name La stringa del nome da cercare.
|
||||||
|
* @return Puntatore all'oggetto JSON trovato, oppure NULL se non esiste.
|
||||||
|
*/
|
||||||
json_object *findItemByName(json_object *arr, const char *name);
|
json_object *findItemByName(json_object *arr, const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Rimuove un oggetto da un array JSON basandosi sul campo "name".
|
||||||
|
* @param arr L'array JSON da cui rimuovere l'elemento.
|
||||||
|
* @param name Il nome dell'elemento da eliminare.
|
||||||
|
* @return 0 in caso di successo, 1 se l'elemento non viene trovato, -1 in caso di errore.
|
||||||
|
*/
|
||||||
int removeItemByName(json_object *arr, const char *name);
|
int removeItemByName(json_object *arr, const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Modifica il campo "name" di un elemento all'interno di un array JSON.
|
||||||
|
* @param arr L'array JSON contenente l'elemento.
|
||||||
|
* @param oldName Il nome attuale dell'elemento da rinominare.
|
||||||
|
* @param newName Il nuovo nome da assegnare.
|
||||||
|
* @return 0 in caso di successo, 1 se l'elemento non viene trovato, -1 in caso di errore.
|
||||||
|
*/
|
||||||
int renameItemByName(json_object *arr, const char *oldName, const char *newName);
|
int renameItemByName(json_object *arr, const char *oldName, const char *newName);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+185
-3
@@ -1,7 +1,6 @@
|
|||||||
#ifndef LOGIC_H
|
#ifndef LOGIC_H
|
||||||
#define LOGIC_H
|
#define LOGIC_H
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -16,33 +15,216 @@ struct product {
|
|||||||
char name;
|
char name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
/* Prodotti */
|
/* Prodotti */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Restituisce l'array JSON contenente tutti i prodotti.
|
||||||
|
* @param fname Percorso del file JSON dei prodotti.
|
||||||
|
* @return Puntatore all'oggetto JSON (array) dei prodotti (da liberare con json_object_put()), oppure NULL in caso di errore.
|
||||||
|
*/
|
||||||
json_object *getProducts(const char *fname);
|
json_object *getProducts(const char *fname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stampa a schermo (tramite ncurses) la lista dei prodotti con relativo prezzo, inventario e tag bundle.
|
||||||
|
* @param fname Percorso del file JSON dei prodotti.
|
||||||
|
*/
|
||||||
void listProducts(const char *fname);
|
void listProducts(const char *fname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Aggiunge un nuovo prodotto con prezzo e inventario illimitato.
|
||||||
|
* @param fname Percorso del file JSON dei prodotti.
|
||||||
|
* @param name Nome del prodotto.
|
||||||
|
* @param price Prezzo del prodotto.
|
||||||
|
* @return 0 in caso di successo, 1 se il prodotto esiste già, -1 in caso di errore.
|
||||||
|
*/
|
||||||
int addProduct(const char *fname, const char *name, double price);
|
int addProduct(const char *fname, const char *name, double price);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Aggiunge un nuovo prodotto specificando prezzo e quantità iniziale in magazzino.
|
||||||
|
* @param fname Percorso del file JSON dei prodotti.
|
||||||
|
* @param name Nome del prodotto.
|
||||||
|
* @param price Prezzo del prodotto.
|
||||||
|
* @param stock Quantità iniziale in magazzino (-1 per inventario illimitato).
|
||||||
|
* @return 0 in caso di successo, 1 se il prodotto esiste già, -1 in caso di errore.
|
||||||
|
*/
|
||||||
int addProductWithInventory(const char *fname, const char *name, double price, int stock);
|
int addProductWithInventory(const char *fname, const char *name, double price, int stock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Aggiunge un prodotto composto (bundle) costituito da altri componenti.
|
||||||
|
* @param fname Percorso del file JSON dei prodotti.
|
||||||
|
* @param name Nome del bundle.
|
||||||
|
* @param price Prezzo del bundle.
|
||||||
|
* @param components Oggetto JSON (array) descrivente i componenti e le relative quantità.
|
||||||
|
* @return 0 in caso di successo, 1 se il prodotto esiste già, -1 in caso di errore.
|
||||||
|
*/
|
||||||
int addBundleProduct(const char *fname, const char *name, double price, json_object *components);
|
int addBundleProduct(const char *fname, const char *name, double price, json_object *components);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ottiene il prezzo di un prodotto specifico.
|
||||||
|
* @param fname Percorso del file JSON dei prodotti.
|
||||||
|
* @param name Nome del prodotto da cercare.
|
||||||
|
* @return Il prezzo del prodotto, oppure -1.0 se non trovato o in caso di errore.
|
||||||
|
*/
|
||||||
double getPrice(const char *fname, const char *name);
|
double getPrice(const char *fname, const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Aggiorna nome e prezzo di un prodotto esistente, sincronizzando anche le vendite se il nome cambia.
|
||||||
|
* @param productsFile Percorso del file JSON dei prodotti.
|
||||||
|
* @param soldFile Percorso del file JSON delle vendite.
|
||||||
|
* @param oldName Nome attuale del prodotto.
|
||||||
|
* @param newName Nuovo nome da assegnare al prodotto.
|
||||||
|
* @param price Nuovo prezzo del prodotto.
|
||||||
|
* @return 0 in caso di successo, codice di errore/stato altrimenti.
|
||||||
|
*/
|
||||||
int updateProduct(const char *productsFile, const char *soldFile, const char *oldName, const char *newName, double price);
|
int updateProduct(const char *productsFile, const char *soldFile, const char *oldName, const char *newName, double price);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Aggiorna nome, prezzo e inventario di un prodotto esistente.
|
||||||
|
* @param productsFile Percorso del file JSON dei prodotti.
|
||||||
|
* @param soldFile Percorso del file JSON delle vendite.
|
||||||
|
* @param oldName Nome attuale del prodotto.
|
||||||
|
* @param newName Nuovo nome da assegnare.
|
||||||
|
* @param price Nuovo prezzo.
|
||||||
|
* @param stock Quantità in magazzino.
|
||||||
|
* @return 0 in caso di successo, codice di errore/stato altrimenti.
|
||||||
|
*/
|
||||||
int updateProductWithInventory(const char *productsFile, const char *soldFile, const char *oldName, const char *newName, double price, int stock);
|
int updateProductWithInventory(const char *productsFile, const char *soldFile, const char *oldName, const char *newName, double price, int stock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Legge lo stato dell'inventario (quantità e tracciamento) di un prodotto.
|
||||||
|
* @param fname Percorso del file JSON dei prodotti.
|
||||||
|
* @param name Nome del prodotto.
|
||||||
|
* @param stock Puntatore a intero in cui salvare la quantità di magazzino.
|
||||||
|
* @param tracked Puntatore a intero in cui salvare se l'inventario è tracciato (1) o meno (0).
|
||||||
|
* @return 0 in caso di successo, 1 se il prodotto non viene trovato, -1 in caso di errore.
|
||||||
|
*/
|
||||||
int getProductInventory(const char *fname, const char *name, int *stock, int *tracked);
|
int getProductInventory(const char *fname, const char *name, int *stock, int *tracked);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Imposta la quantità e lo stato di tracciamento dell'inventario per un prodotto.
|
||||||
|
* @param fname Percorso del file JSON dei prodotti.
|
||||||
|
* @param name Nome del prodotto.
|
||||||
|
* @param stock Quantità di magazzino da impostare.
|
||||||
|
* @param tracked Flag di tracciamento (1 per tracciato, 0 altrimenti).
|
||||||
|
* @return 0 in caso di successo, 1 se il prodotto non è trovato, -1 in caso di errore.
|
||||||
|
*/
|
||||||
int setProductInventory(const char *fname, const char *name, int stock, int tracked);
|
int setProductInventory(const char *fname, const char *name, int stock, int tracked);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Consuma (scala) una determinata quantità dall'inventario di un prodotto o dei suoi componenti (se bundle).
|
||||||
|
* @param fname Percorso del file JSON dei prodotti.
|
||||||
|
* @param name Nome del prodotto.
|
||||||
|
* @param qty Quantità da consumare.
|
||||||
|
* @return 0 in caso di successo, codice di errore o disponibilità insufficiente altrimenti.
|
||||||
|
*/
|
||||||
int consumeProductInventory(const char *fname, const char *name, int qty);
|
int consumeProductInventory(const char *fname, const char *name, int qty);
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
/* Copie vendute */
|
/* Copie vendute */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Restituisce il numero di copie vendute di un determinato prodotto.
|
||||||
|
* @param fname Percorso del file JSON delle vendite.
|
||||||
|
* @param name Nome del prodotto.
|
||||||
|
* @return Il numero di copie vendute (0 se non presente, -1 in caso di errore).
|
||||||
|
*/
|
||||||
int getCount(const char *fname, const char *name);
|
int getCount(const char *fname, const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stampa a schermo (tramite ncurses) la lista delle vendite registrate per ciascun prodotto.
|
||||||
|
* @param fname Percorso del file JSON delle vendite.
|
||||||
|
*/
|
||||||
void listSold(const char *fname);
|
void listSold(const char *fname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Aggiunge una quantità di copie vendute per un prodotto (creando la voce se non esiste).
|
||||||
|
* @param fname Percorso del file JSON delle vendite.
|
||||||
|
* @param name Nome del prodotto.
|
||||||
|
* @param qty Quantità venduta da aggiungere.
|
||||||
|
* @return 0 in caso di successo, -1 in caso di errore.
|
||||||
|
*/
|
||||||
int addSold(const char *fname, const char *name, int qty);
|
int addSold(const char *fname, const char *name, int qty);
|
||||||
int updateSold(const char *fname, const char *name, int qty);
|
|
||||||
int deleteSold(const char *fname, const char *name);
|
/**
|
||||||
|
* @brief Elimina la registrazione delle vendite di un prodotto e ripristina l'inventario corrispondente.
|
||||||
|
* @param productsFile Percorso del file JSON dei prodotti.
|
||||||
|
* @param soldFile Percorso del file JSON delle vendite.
|
||||||
|
* @param name Nome del prodotto di cui eliminare le vendite.
|
||||||
|
* @return 0 in caso di successo, 1 se la vendita non è presente, -1 o codice di errore in caso di fallimento.
|
||||||
|
*/
|
||||||
|
int deleteSold(const char *productsFile, const char *soldFile, const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Aggiorna la quantità di copie vendute per un prodotto, regolando di conseguenza il magazzino.
|
||||||
|
* @param productsFile Percorso del file JSON dei prodotti.
|
||||||
|
* @param soldFile Percorso del file JSON delle vendite.
|
||||||
|
* @param name Nome del prodotto.
|
||||||
|
* @param qty Nuova quantità totale venduta.
|
||||||
|
* @return 0 in caso di successo, 1 se non presente, codice di errore altrimenti.
|
||||||
|
*/
|
||||||
|
int updateSold(const char *productsFile, const char *soldFile, const char *name, int qty);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Registra una vendita scalando l'inventario dei prodotti e incrementando le vendite, con supporto di rollback in caso di problemi.
|
||||||
|
* @param productsFile Percorso del file JSON dei prodotti.
|
||||||
|
* @param soldFile Percorso del file JSON delle vendite.
|
||||||
|
* @param name Nome del prodotto venduto.
|
||||||
|
* @param qty Quantità venduta.
|
||||||
|
* @return 0 in caso di successo, codice di errore in caso di fallimento.
|
||||||
|
*/
|
||||||
int recordSale(const char *productsFile, const char *soldFile, const char *name, int qty);
|
int recordSale(const char *productsFile, const char *soldFile, const char *name, int qty);
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
/* Entrate */
|
/* Entrate */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calcola le entrate totali sommando il prodotto tra prezzo e copie vendute per ciascun articolo.
|
||||||
|
* @param productsFile Percorso del file JSON dei prodotti.
|
||||||
|
* @param soldFile Percorso del file JSON delle vendite.
|
||||||
|
* @return Il totale delle entrate, oppure -1.0 in caso di errore.
|
||||||
|
*/
|
||||||
double getTotalRevenue(const char *productsFile, const char *soldFile);
|
double getTotalRevenue(const char *productsFile, const char *soldFile);
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Export */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Esporta i dati delle vendite e dei prodotti in un file in formato CSV.
|
||||||
|
* @param productsFile Percorso del file JSON dei prodotti.
|
||||||
|
* @param soldFile Percorso del file JSON delle vendite.
|
||||||
|
* @param outFile Percorso del file CSV di output.
|
||||||
|
* @return 0 in caso di successo, un valore negativo in caso di errore.
|
||||||
|
*/
|
||||||
|
int exportSalesToCsv(const char *productsFile, const char *soldFile, const char *outFile);
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
/* Config */
|
/* Config */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Assicura che il file di configurazione dell'applicazione esista, creandolo se necessario.
|
||||||
|
* @param fname Percorso del file di configurazione.
|
||||||
|
* @return 0 in caso di successo, codice di errore altrimenti.
|
||||||
|
*/
|
||||||
int ensureAppConfig(const char *fname);
|
int ensureAppConfig(const char *fname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Carica la configurazione dell'applicazione dal file specificato.
|
||||||
|
* @param fname Percorso del file di configurazione.
|
||||||
|
* @return 0 in caso di successo, -1 in caso di errore.
|
||||||
|
*/
|
||||||
int loadAppConfig(const char *fname);
|
int loadAppConfig(const char *fname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Salva la configurazione corrente dell'applicazione sul file specificato.
|
||||||
|
* @param fname Percorso del file di configurazione.
|
||||||
|
* @return 0 in caso di successo, -1 in caso di errore.
|
||||||
|
*/
|
||||||
int saveAppConfig(const char *fname);
|
int saveAppConfig(const char *fname);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -6,18 +6,95 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crea e restituisce una nuova finestra ncurses con i bordi tracciati.
|
||||||
|
* @param height Altezza della finestra.
|
||||||
|
* @param width Larghezza della finestra.
|
||||||
|
* @param starty Coordinata Y iniziale sullo schermo.
|
||||||
|
* @param startx Coordinata X iniziale sullo schermo.
|
||||||
|
* @return Puntatore all'oggetto WINDOW creato.
|
||||||
|
*/
|
||||||
WINDOW *create_newwin(int height, int width, int starty, int startx);
|
WINDOW *create_newwin(int height, int width, int starty, int startx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Distrugge una finestra ncurses creata in precedenza e libera la memoria associata.
|
||||||
|
* @param local_win Puntatore alla finestra da eliminare.
|
||||||
|
*/
|
||||||
void destroy_win(WINDOW *local_win);
|
void destroy_win(WINDOW *local_win);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stampa del testo all'interno di una finestra gestendo l'andata a capo automatica (word wrapping) per parola.
|
||||||
|
* @param win Finestra in cui stampare.
|
||||||
|
* @param start_y Coordinata Y iniziale all'interno della finestra.
|
||||||
|
* @param start_x Coordinata X iniziale all'interno della finestra.
|
||||||
|
* @param str Stringa di testo da stampare.
|
||||||
|
*/
|
||||||
void wwrap_print(WINDOW *win, int start_y, int start_x, const char *str);
|
void wwrap_print(WINDOW *win, int start_y, int start_x, const char *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gestisce un interruttore grafico interattivo (stato ON/OFF) modificabile da tastiera.
|
||||||
|
* @param win Finestra di visualizzazione.
|
||||||
|
* @param y Coordinata Y dell'interruttore.
|
||||||
|
* @param x Coordinata X dell'interruttore.
|
||||||
|
* @param state Stato iniziale (1 per ON, 0 per OFF).
|
||||||
|
* @return Lo stato finale dell'interruttore dopo l'interazione dell'utente.
|
||||||
|
*/
|
||||||
int uiToggleSwitch(WINDOW *win, int y, int x, int state);
|
int uiToggleSwitch(WINDOW *win, int y, int x, int state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gestisce un campo di input di testo interattivo all'interno di una finestra ncurses.
|
||||||
|
* @param win Finestra in cui inserire il testo.
|
||||||
|
* @param y Coordinata Y.
|
||||||
|
* @param x Coordinata X.
|
||||||
|
* @param input Buffer contenente l'eventuale testo iniziale e in cui memorizzare il risultato digitato.
|
||||||
|
* @param max_len Lunghezza massima consentita per l'input.
|
||||||
|
*/
|
||||||
void uiTextInput(WINDOW *win, int y, int x, char *input, int max_len);
|
void uiTextInput(WINDOW *win, int y, int x, char *input, int max_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mostra un menu di scelta multipla navigabile da tastiera tramite frecce o tasti vim (j/k).
|
||||||
|
* @param win Finestra in cui mostrare il menu.
|
||||||
|
* @param start_y Coordinata Y iniziale.
|
||||||
|
* @param start_x Coordinata X iniziale.
|
||||||
|
* @param options Array di stringhe contenente le opzioni del menu.
|
||||||
|
* @param n_options Numero totale di opzioni disponibili.
|
||||||
|
* @return L'indice (1-based) della voce selezionata dall'utente.
|
||||||
|
*/
|
||||||
int uiSelectMenu(WINDOW *win, int start_y, int start_x, char **options, int n_options);
|
int uiSelectMenu(WINDOW *win, int start_y, int start_x, char **options, int n_options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stampa un menu all'interno di una finestra evidenziando una voce specifica.
|
||||||
|
* @param menu_win Finestra del menu.
|
||||||
|
* @param y Coordinata Y.
|
||||||
|
* @param x Coordinata X.
|
||||||
|
* @param highlight Indice della voce da evidenziare graficamente.
|
||||||
|
*/
|
||||||
void print_menu(WINDOW *menu_win, int y, int x, int highlight);
|
void print_menu(WINDOW *menu_win, int y, int x, int highlight);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mostra una finestra di avviso (warning) utilizzando una stringa formattata (stile printf).
|
||||||
|
* @param fmt Stringa di formattazione.
|
||||||
|
* @param ... Argomenti variabili da formattare.
|
||||||
|
*/
|
||||||
void warningf(const char *fmt, ...);
|
void warningf(const char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Apre una finestra di popup con un messaggio di avviso e attende la pressione di un tasto per chiudersi.
|
||||||
|
* @param string Messaggio di errore o avviso da mostrare.
|
||||||
|
*/
|
||||||
void warning(char *string);
|
void warning(char *string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Aggiorna la barra di stato in basso sullo schermo con un messaggio formattato (stile printf).
|
||||||
|
* @param fmt Stringa di formattazione.
|
||||||
|
* @param ... Argomenti variabili da formattare.
|
||||||
|
*/
|
||||||
void statusf(const char *fmt, ...);
|
void statusf(const char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Scrive un messaggio direttamente nella barra di stato in basso sullo schermo.
|
||||||
|
* @param msg Messaggio da visualizzare nella status bar.
|
||||||
|
*/
|
||||||
void status(char *msg);
|
void status(char *msg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -14,6 +14,7 @@ void runAboutWindow();
|
|||||||
void runViewSalesWindow();
|
void runViewSalesWindow();
|
||||||
void runViewProductsWindow();
|
void runViewProductsWindow();
|
||||||
void runAddProductWindow();
|
void runAddProductWindow();
|
||||||
|
void runExportCsvWindow();
|
||||||
void example_window();
|
void example_window();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -36,6 +36,6 @@ bundle: $(OBJECTS)
|
|||||||
@rm -fr dist/
|
@rm -fr dist/
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD_DIR) $(EXEC) dist *.json
|
rm -rf $(BUILD_DIR) $(EXEC) dist *.json .fpm
|
||||||
|
|
||||||
.PHONY: all clean bundle
|
.PHONY: all clean bundle
|
||||||
+221
-22
@@ -5,6 +5,8 @@
|
|||||||
#include <json-c/json.h>
|
#include <json-c/json.h>
|
||||||
|
|
||||||
#include "../include/logic.h"
|
#include "../include/logic.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "../include/globals.h"
|
#include "../include/globals.h"
|
||||||
#include "../include/jsonFile.h"
|
#include "../include/jsonFile.h"
|
||||||
|
|
||||||
@@ -39,6 +41,90 @@ static int readInventory(json_object *item, int *stock, int *tracked) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int exportSalesToCsv(const char *productsFile, const char *soldFile, const char *outFile)
|
||||||
|
{
|
||||||
|
json_object *products = getProducts(productsFile);
|
||||||
|
json_object *sales = getProducts(soldFile);
|
||||||
|
if (!products || !json_object_is_type(products, json_type_array)) {
|
||||||
|
if (products) json_object_put(products);
|
||||||
|
if (sales) json_object_put(sales);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *f = fopen(outFile, "w");
|
||||||
|
if (!f) {
|
||||||
|
if (products) json_object_put(products);
|
||||||
|
if (sales) json_object_put(sales);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(f, "Nome;Inventario iniziale;Vendite;Prezzo;Componenti\n");
|
||||||
|
|
||||||
|
int n = json_object_array_length(products);
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
json_object *item = json_object_array_get_idx(products, i);
|
||||||
|
json_object *jname = NULL;
|
||||||
|
json_object *jprice = NULL;
|
||||||
|
json_object *jbundle = NULL;
|
||||||
|
|
||||||
|
const char *name = (json_object_object_get_ex(item, "name", &jname) && jname) ? json_object_get_string(jname) : "";
|
||||||
|
double price = (json_object_object_get_ex(item, "price", &jprice) && jprice) ? json_object_get_double(jprice) : 0.0;
|
||||||
|
int isBundle = (json_object_object_get_ex(item, "bundle", &jbundle) && jbundle) ? json_object_get_int(jbundle) : 0;
|
||||||
|
|
||||||
|
/* sold count */
|
||||||
|
int sold = getCount(soldFile, name);
|
||||||
|
|
||||||
|
/* inventory */
|
||||||
|
const char *inv_text = NULL;
|
||||||
|
char inv_buf[64];
|
||||||
|
if (isBundle) {
|
||||||
|
inv_text = "non definito";
|
||||||
|
} else {
|
||||||
|
int stock = -1;
|
||||||
|
json_object *stock_obj = NULL;
|
||||||
|
if (json_object_object_get_ex(item, "stock", &stock_obj) && stock_obj) {
|
||||||
|
stock = json_object_get_int(stock_obj);
|
||||||
|
}
|
||||||
|
if (stock < 0) {
|
||||||
|
inv_text = "non definito";
|
||||||
|
} else {
|
||||||
|
/* initial = current stock + sold */
|
||||||
|
snprintf(inv_buf, sizeof(inv_buf), "%d", stock + sold);
|
||||||
|
inv_text = inv_buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* components */
|
||||||
|
char comp_buf[512];
|
||||||
|
comp_buf[0] = '\0';
|
||||||
|
if (isBundle) {
|
||||||
|
json_object *comp = NULL;
|
||||||
|
if (json_object_object_get_ex(item, "components", &comp) && comp && json_object_is_type(comp, json_type_array)) {
|
||||||
|
int m = json_object_array_length(comp);
|
||||||
|
for (int j = 0; j < m; ++j) {
|
||||||
|
json_object *c = json_object_array_get_idx(comp, j);
|
||||||
|
json_object *cjname = NULL;
|
||||||
|
const char *cname = (json_object_object_get_ex(c, "name", &cjname) && cjname) ? json_object_get_string(cjname) : "";
|
||||||
|
if (j) strncat(comp_buf, ";", sizeof(comp_buf)-strlen(comp_buf)-1);
|
||||||
|
strncat(comp_buf, cname ? cname : "", sizeof(comp_buf)-strlen(comp_buf)-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write CSV line; escape semicolons in name/comp if needed (simple) */
|
||||||
|
fprintf(f, "%s;%s;%d;%.2f;%s\n",
|
||||||
|
name ? name : "",
|
||||||
|
inv_text,
|
||||||
|
sold,
|
||||||
|
price,
|
||||||
|
comp_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
if (products) json_object_put(products);
|
||||||
|
if (sales) json_object_put(sales);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
static void writeInventory(json_object *item, int stock, int tracked) {
|
static void writeInventory(json_object *item, int stock, int tracked) {
|
||||||
if (!item)
|
if (!item)
|
||||||
return;
|
return;
|
||||||
@@ -267,6 +353,46 @@ static int consumeTree(json_object *products, json_object *item, int qty) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int restoreTree(json_object *products, json_object *item, int qty) {
|
||||||
|
if (!products || !item || qty <= 0) return -1;
|
||||||
|
|
||||||
|
if (!isBundleItem(item)) {
|
||||||
|
json_object *jstock = NULL;
|
||||||
|
if (!json_object_object_get_ex(item, "stock", &jstock) || !jstock)
|
||||||
|
return 0;
|
||||||
|
int stock = json_object_get_int(jstock);
|
||||||
|
if (stock < 0) return 0; /* non tracciato */
|
||||||
|
json_object_object_add(item, "stock", json_object_new_int(stock + qty));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object *components = getBundleComponents(item);
|
||||||
|
if (!components) return 0;
|
||||||
|
|
||||||
|
size_t count = json_object_array_length(components);
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
json_object *c = json_object_array_get_idx(components, i);
|
||||||
|
json_object *jname = NULL;
|
||||||
|
if (!json_object_object_get_ex(c, "name", &jname) || !jname) return -1;
|
||||||
|
json_object *child = findItemByName(products, json_object_get_string(jname));
|
||||||
|
if (!child) return 1;
|
||||||
|
int res = restoreTree(products, child, qty * getComponentQty(c));
|
||||||
|
if (res != 0) return res;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int restoreProductInventory(const char *fname, const char *name, int qty) {
|
||||||
|
json_object *arr = loadJsonArray(fname);
|
||||||
|
if (!arr) return -1;
|
||||||
|
json_object *item = findItemByName(arr, name);
|
||||||
|
if (!item) { json_object_put(arr); return 1; }
|
||||||
|
int res = restoreTree(arr, item, qty);
|
||||||
|
if (res == 0) res = saveJsonArray(fname, arr);
|
||||||
|
json_object_put(arr);
|
||||||
|
return res == 0 ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
static char *loadFileText(const char *fname) {
|
static char *loadFileText(const char *fname) {
|
||||||
FILE *f = fopen(fname, "rb");
|
FILE *f = fopen(fname, "rb");
|
||||||
long size;
|
long size;
|
||||||
@@ -692,38 +818,111 @@ int recordSale(const char *productsFile, const char *soldFile, const char *name,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int updateSold(const char *fname, const char *name, int qty) {
|
int deleteSold(const char *productsFile, const char *soldFile, const char *name) {
|
||||||
json_object *arr = loadJsonArray(fname);
|
json_object *sales = loadJsonArray(soldFile);
|
||||||
if (!arr)
|
if (!sales)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
json_object *item = findItemByName(arr, name);
|
json_object *item = findItemByName(sales, name);
|
||||||
if (!item) {
|
if (!item) {
|
||||||
json_object_put(arr);
|
json_object_put(sales);
|
||||||
return 1;
|
return 1; /* vendita non presente */
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object *jsold = NULL;
|
||||||
|
int qty = 0;
|
||||||
|
if (json_object_object_get_ex(item, "sold", &jsold) && jsold)
|
||||||
|
qty = json_object_get_int(jsold);
|
||||||
|
|
||||||
|
/* backup dei prodotti per il rollback */
|
||||||
|
char *backup = NULL;
|
||||||
|
if (qty > 0) {
|
||||||
|
backup = loadFileText(productsFile);
|
||||||
|
if (!backup) {
|
||||||
|
json_object_put(sales);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = restoreProductInventory(productsFile, name, qty);
|
||||||
|
/* 1 = prodotto non più presente: niente da ripristinare, si procede */
|
||||||
|
if (res != 0 && res != 1) {
|
||||||
|
free(backup);
|
||||||
|
json_object_put(sales);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = removeItemByName(sales, name);
|
||||||
|
if (res == 0)
|
||||||
|
res = saveJsonArray(soldFile, sales);
|
||||||
|
json_object_put(sales);
|
||||||
|
|
||||||
|
if (res != 0) {
|
||||||
|
if (backup)
|
||||||
|
saveFileText(productsFile, backup); /* rollback inventario */
|
||||||
|
free(backup);
|
||||||
|
return (res < 0) ? res : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(backup);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int updateSold(const char *productsFile, const char *soldFile, const char *name, int qty) {
|
||||||
|
if (qty < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
json_object *sales = loadJsonArray(soldFile);
|
||||||
|
if (!sales)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
json_object *item = findItemByName(sales, name);
|
||||||
|
if (!item) {
|
||||||
|
json_object_put(sales);
|
||||||
|
return 1; /* vendita non presente */
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object *jsold = NULL;
|
||||||
|
int oldQty = 0;
|
||||||
|
if (json_object_object_get_ex(item, "sold", &jsold) && jsold)
|
||||||
|
oldQty = json_object_get_int(jsold);
|
||||||
|
|
||||||
|
int delta = qty - oldQty; /* >0: vendute di più, <0: vendute di meno */
|
||||||
|
char *backup = NULL;
|
||||||
|
|
||||||
|
if (delta != 0) {
|
||||||
|
backup = loadFileText(productsFile);
|
||||||
|
if (!backup) {
|
||||||
|
json_object_put(sales);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res;
|
||||||
|
if (delta > 0)
|
||||||
|
res = consumeProductInventory(productsFile, name, delta); /* controlla anche la disponibilità */
|
||||||
|
else
|
||||||
|
res = restoreProductInventory(productsFile, name, -delta);
|
||||||
|
|
||||||
|
if (res != 0 && !(delta < 0 && res == 1)) {
|
||||||
|
free(backup);
|
||||||
|
json_object_put(sales);
|
||||||
|
return (res == 1) ? -1 : res; /* evita ambiguità con "vendita non presente" */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
json_object_object_add(item, "sold", json_object_new_int(qty));
|
json_object_object_add(item, "sold", json_object_new_int(qty));
|
||||||
|
int res = saveJsonArray(soldFile, sales);
|
||||||
|
json_object_put(sales);
|
||||||
|
|
||||||
int res = saveJsonArray(fname, arr);
|
|
||||||
json_object_put(arr);
|
|
||||||
return (res == 0) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int deleteSold(const char *fname, const char *name) {
|
|
||||||
json_object *arr = loadJsonArray(fname);
|
|
||||||
if (!arr)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int res = removeItemByName(arr, name);
|
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
json_object_put(arr);
|
if (backup)
|
||||||
return res;
|
saveFileText(productsFile, backup); /* rollback inventario */
|
||||||
|
free(backup);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = saveJsonArray(fname, arr);
|
free(backup);
|
||||||
json_object_put(arr);
|
return 0;
|
||||||
return (res == 0) ? 0 : -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
|
|||||||
+73
-18
@@ -11,6 +11,8 @@
|
|||||||
#define MAX_LEN 64
|
#define MAX_LEN 64
|
||||||
#define LINE_LEN 96
|
#define LINE_LEN 96
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper
|
* Helper
|
||||||
*/
|
*/
|
||||||
@@ -29,6 +31,15 @@ static void replaceCommaWithDot(char *text) {
|
|||||||
*p = '.';
|
*p = '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int askAction(const char *title, char **opts, int n_opts) {
|
||||||
|
WINDOW *win = create_newwin(8, COLS / 3 + 8, LINES / 2 - 4, COLS / 2);
|
||||||
|
mvwprintw(win, 1, 2, "%s", title);
|
||||||
|
int choice = uiSelectMenu(win, 3, 2, opts, n_opts);
|
||||||
|
werase(win);
|
||||||
|
destroy_win(win);
|
||||||
|
return choice;
|
||||||
|
}
|
||||||
|
|
||||||
static int parseIntValue(const char *text, int *value) {
|
static int parseIntValue(const char *text, int *value) {
|
||||||
char *end = NULL;
|
char *end = NULL;
|
||||||
long parsed = strtol(text, &end, 10);
|
long parsed = strtol(text, &end, 10);
|
||||||
@@ -216,6 +227,51 @@ static int promptDataFilesForm(char *productsFile, size_t productsFileSize, char
|
|||||||
return choice;
|
return choice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int promptExportFileName(char *outFile, size_t outFileSize) {
|
||||||
|
WINDOW *win = create_newwin(9, COLS / 2, 0, COLS / 2);
|
||||||
|
char *opts[] = {"Esporta", "Annulla"};
|
||||||
|
|
||||||
|
mvwprintw(win, 1, 2, "Esporta vendite a CSV");
|
||||||
|
mvwprintw(win, 3, 2, "File di destinazione:");
|
||||||
|
if (outFile && outFile[0])
|
||||||
|
uiTextInput(win, 4, 2, outFile, (int)outFileSize - 1);
|
||||||
|
else {
|
||||||
|
snprintf(outFile, outFileSize, "export.csv");
|
||||||
|
uiTextInput(win, 4, 2, outFile, (int)outFileSize - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int choice = uiSelectMenu(win, 6, 4, opts, 2);
|
||||||
|
werase(win);
|
||||||
|
destroy_win(win);
|
||||||
|
return choice;
|
||||||
|
}
|
||||||
|
|
||||||
|
void runExportCsvWindow() {
|
||||||
|
char outFile[MAX_LEN + 1];
|
||||||
|
snprintf(outFile, sizeof outFile, "export.csv");
|
||||||
|
|
||||||
|
int choice = promptExportFileName(outFile, sizeof outFile);
|
||||||
|
if (choice != 1) {
|
||||||
|
statusf("Operazione annullata");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char title[128];
|
||||||
|
char *opts[] = {"Conferma", "Annulla"};
|
||||||
|
snprintf(title, sizeof title, "Esportare le vendite in '%s' ?", outFile);
|
||||||
|
int ok = askAction(title, opts, 2);
|
||||||
|
if (ok != 1) {
|
||||||
|
statusf("Operazione annullata");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = exportSalesToCsv(productPricesFileLocation, countFileLocation, outFile);
|
||||||
|
if (res == 0)
|
||||||
|
statusf("Export CSV salvato in '%s'", outFile);
|
||||||
|
else
|
||||||
|
warningf("Errore nell'esportazione (codice %d)", res);
|
||||||
|
}
|
||||||
|
|
||||||
static char **buildSalesLines(json_object *sales, int *n) {
|
static char **buildSalesLines(json_object *sales, int *n) {
|
||||||
int count = (int)json_object_array_length(sales);
|
int count = (int)json_object_array_length(sales);
|
||||||
char **lines = malloc((count > 0 ? count : 1) * sizeof *lines);
|
char **lines = malloc((count > 0 ? count : 1) * sizeof *lines);
|
||||||
@@ -316,15 +372,6 @@ static int listWindow(const char *title, char **lines, int n, const char *footer
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int askAction(const char *title, char **opts, int n_opts) {
|
|
||||||
WINDOW *win = create_newwin(8, COLS / 3 + 8, LINES / 2 - 4, COLS / 2);
|
|
||||||
mvwprintw(win, 1, 2, "%s", title);
|
|
||||||
int choice = uiSelectMenu(win, 3, 2, opts, n_opts);
|
|
||||||
werase(win);
|
|
||||||
destroy_win(win);
|
|
||||||
return choice;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int confirmDeletion(const char *subject) {
|
static int confirmDeletion(const char *subject) {
|
||||||
char *opts[] = {"Elimina", "Annulla"};
|
char *opts[] = {"Elimina", "Annulla"};
|
||||||
char title[128];
|
char title[128];
|
||||||
@@ -593,13 +640,16 @@ static void showSaleEditWindow(const char *name, int sold) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = updateSold(countFileLocation, name, qty);
|
int res = updateSold(productPricesFileLocation, countFileLocation, name, qty);
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
statusf("Vendita aggiornata: '%s' = %d", name, qty);
|
statusf("Vendita aggiornata: '%s' = %d", name, qty);
|
||||||
else if (res == 1)
|
else if (res == 1)
|
||||||
warningf("La vendita '%s' non esiste piu'.", name);
|
warningf("La vendita '%s' non esiste piu'.", name);
|
||||||
|
else if (res == 2)
|
||||||
|
warningf("Stock insufficiente per portare '%s' a %d vendite.", name, qty);
|
||||||
else
|
else
|
||||||
warningf("Errore nella scrittura del file '%s'.", countFileLocation);
|
warningf("Errore nell'aggiornamento di vendite/inventario ('%s', '%s').",
|
||||||
|
countFileLocation, productPricesFileLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deleteSaleByName(const char *name) {
|
static void deleteSaleByName(const char *name) {
|
||||||
@@ -608,13 +658,14 @@ static void deleteSaleByName(const char *name) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = deleteSold(countFileLocation, name);
|
int res = deleteSold(productPricesFileLocation, countFileLocation, name);
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
statusf("Vendita eliminata: '%s'", name);
|
statusf("Vendita eliminata: '%s' (inventario ripristinato)", name);
|
||||||
else if (res == 1)
|
else if (res == 1)
|
||||||
warningf("La vendita '%s' non esiste piu'.", name);
|
warningf("La vendita '%s' non esiste piu'.", name);
|
||||||
else
|
else
|
||||||
warningf("Errore nella scrittura del file '%s'.", countFileLocation);
|
warningf("Errore nell'aggiornamento di vendite/inventario ('%s', '%s').",
|
||||||
|
countFileLocation, productPricesFileLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void showSaleActionWindow(const char *name, int sold) {
|
static void showSaleActionWindow(const char *name, int sold) {
|
||||||
@@ -826,6 +877,9 @@ static void runMainMenuChoice(int choice) {
|
|||||||
runOptionsMenu();
|
runOptionsMenu();
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
|
runExportCsvWindow();
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
runAboutWindow();
|
runAboutWindow();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -836,9 +890,10 @@ int runMainMenu() {
|
|||||||
"Segna vendita",
|
"Segna vendita",
|
||||||
"Vedi vendite",
|
"Vedi vendite",
|
||||||
"Vedi prodotti",
|
"Vedi prodotti",
|
||||||
"Aggiungi prodotti",
|
"Aggiungi nuovo prodotto",
|
||||||
"Crea nuovo bundle",
|
"Aggiungi nuovo bundle",
|
||||||
"Opzioni",
|
"Opzioni",
|
||||||
|
"Esporta CSV",
|
||||||
"About",
|
"About",
|
||||||
"Exit"
|
"Exit"
|
||||||
};
|
};
|
||||||
@@ -861,11 +916,11 @@ int runMainMenu() {
|
|||||||
clrtoeol();
|
clrtoeol();
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
if (choice >= 1 && choice <= 7)
|
if (choice >= 1 && choice <= 8)
|
||||||
runMainMenuChoice(choice);
|
runMainMenuChoice(choice);
|
||||||
|
|
||||||
destroy_win(mainWin);
|
destroy_win(mainWin);
|
||||||
return choice != 8;
|
return choice != 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
void runAboutWindow() {
|
void runAboutWindow() {
|
||||||
|
|||||||
Reference in new issue
Block a user