/******************************************************************************
Barninga_Z! - OPTLIB
filename - PARSEOPT.H
getswitch() - legge lo switch character DOS di default
parseopt() - analizza e memorizza le opzioni (low level)
parseoptions() - analizza e memorizza le opzioni
setswitch() - stabilisce lo switch character DOS di defaul
******************************************************************************/
#ifndef __PARSEOPT__
#define ILLEG_S "Illegal option" // : nella cmd line
#define ERROR_S "Unknown option" // opzione non in optionS
#define ERRCHAR ((char)-1) // opzione errata
struct OPT { // usato per le opzioni, gli argomenti e i valori di convalida
char opt; // restituiti dalle funzioni. A storeopt() deve essere passato
char *arg; // un puntatore ad una struttura OPT. Se e' invocata
int val; // parseopt() l'array di strutture e' allocato in modo
}; // automatico e ne e' restituito il puntatore.
struct VOPT { // template per array strutture contenenti le opzioni e i
char opt; // puntatori alle funzioni di validazione
int (*fun)(struct OPT *tmp,int no);
};
int cdecl getswitch(void);
struct OPT *cdecl parseopt(int argc,char **argv,char *optionS,char sw,char
*illegalS,
char *errorS,struct VOPT valfuncs[]);
struct OPT *cdecl parseoptions(int argc,char **argv,char *optionS,
struct VOPT valfuncs[]);
int cdecl setswitch(char sw);
#define __PARSEOPT__
#endif
/****************** FINE DEL FILE PARSEOPT.H ************************************/
OK, OK, ne ho avuto abbastanza! Torniamo alla lettura...
/******************************************************************************
Barninga_Z! - OPTLIB
file - parseopt.c
funzioni:
getswitch - legge lo switch character DOS di default
gopError - ritorna da storeopt() se vi e' un errore nella command line
parseopt - analizza e memorizza le opzioni (low level)
parseoptions - analizza e memorizza le opzioni
setswitch - stabilisce lo switch character DOS di default
storeopt - analizza e memorizza le opzioni (internal only)
******************************************************************************/
#pragma warn -pia // evita warning per assegnamenti con test implicito
#include <alloc.h>
#include <string.h>
#include "parseopt.h"
#define EINVFNC 1 // Invalid function number
#define EINVAL 19 // Invalid argument
// i prototipi di storeopt() e gopError() sono qui e non in PARSEOPT.H perche'
// si tratta di funzioni che l'utente non ha bisogno di chiamare direttamente
// in pratica si tratta di routines di servizio per le funzioni high-level
int cdecl gopError(struct OPT *cmd);
int cdecl storeopt(int argc,char **argv,char *optionS,char sw,struct OPT *cmd,
char *illegalS,char *errorS);
int pascal __IOerror(int dosErr); // funzione di libreria; non documentata
static int optind; // indice della prossima opzione. E' inzializzata a 1 in
// ingresso ed utilizzata da storeopt(). Deve essere
// riazzerata in uscita per consentire chiamate multiple a
// parseopt()
/*----------------------------------------------------------------------------*
getswitch() Restituisce lo switch character di default
SINTASSI int cdecl getswitch(void);
INCLUDE parsopt.h
PARAMETRI Nessuno.
SCOPO Ottiene il carattere che il DOS abilita per default ad
introdurre gli switches (opzioni) sulla command line dei
programmi. Se è usata per valorizzare il parametro sw di
parseopt() o storeopt(), tutte le opzioni sulla command
line devono essere precedute dal carattere restituito da
getswitch(). E' inoltre invocata da parseoptions().
RESTITUISCE -1 funzione non supportata dal DOS.
altro lo switch character di default per il DOS.
SORGENTE getdossw.c
NOTE Nessuna.
*----------------------------------------------------------------------------*/
int cdecl getswitch(void)
{
asm {
mov ax,0x3700;
int 0x21;
cmp al,0xFF;
je notsupported;
mov al,dl;
xor ah,ah;
jmp endfunc;
}
notsupported:
_AX = __IOerror(EINVFNC);
endfunc:
return(_AX);
}
/*----------------------------------------------------------------------------*
gopError() Ritorna da storeopt() in caso di errore - INTERNAL
SINTASSI int cdecl gopError(struct OPT *cmd);
INCLUDE parsopt.h
PARAMETRI cmd puntatore all'elemento dell'array di
strutture OPT (template in storeopt.h) nel
quale l'opzione verrebbe memorizzata.
SCOPO Ritorna da storeopt() quando questa individua un errore
nella command line (es.: opzione sconosciuta). Memorizza
il valore -1 nel campo val della struttura e chiama
__IOerror().
RESTITUISCE l'opzione (anche se non valida).
SORGENTE storeopt.c
NOTE Il programma non deve invocare questa funzione; essa è una
funzione di servizio per storeopt().
*----------------------------------------------------------------------------*/
static int cdecl gopError(struct OPT *cmd)
{
cmd->val = __IOerror(EINVAL);
return((int)cmd->opt);
}
/*----------------------------------------------------------------------------*
parseopt() Analizza la command line - LOW LEVEL
SINTASSI int cdecl parseopt(int argc,char **argv,char *optionS,char sw,
char *illegalS,char *errorS,struct VOPT *valfuncs);
INCLUDE parsopt.h
PARAMETRI argc numero di parametri sulla command line + 1.
E' generalmente argc parametro di main().
argv array di puntatori ai parametri della
command line. E' generalmente argv parametro
di main().
optionS puntatore alla stringa contenente tutti i
caratteri opazione riconosciuti dal
programma.
sw lo switch character che introduce ogni
opzione (o gruppo di opzioni).
illegalS puntatore alla stringa rappresentatnte il
messaggio di errore corrispondente all'uso
non lecito dei due punti (:) nella command
line.
errorS puntatore alla stringa utilizzata come
messaggio di errore per un'opzione non
compresa in optionS.
valfuncs puntatore ad un array di struct VOPT
(template definito in parsopt.h). L'array ha
un elemento per ogni opzione che si desidera
testare o convalidare. Ogni elemento è una
struct VOPT, la quale ha due campi: il primo
(char opt) contiene il carattere-opzione; il
secondo (int (*fun)(struct OPT *,int))
contiene il puntatore alla funzione che deve
essere invocata per testare l'opzione. Tale
funzione deve essere di tipo int ed
accettare due parametri, un puntatore a
struct OPT (template in parsopt.h) e un
int). Il primo punta alla struttura
valorizzata da storeopt() estraendo
l'opzione dalla command line, il secondo
rappresenta la posizione dell'opzione nella
command line. L'array DEVE avere, quale
ultimo elemento, una struct VOPT in cui il
campo opt è NULL: la funzione puntata dal
campo fun viene invocata per ciascun
parametro non-opzione incontrato sulla
command line. Inoltre, se il campo opt di
uno qualunque degli elementi dell'array
contiene il carattere ERRCHAR (parsopt.h)
la funzione puntata dal corrispondente campo
fun viene invocata quando l'opzione
restituita da storeopt() è sconosciuta o,
comunque, in caso di errore.
SCOPO Scandisce e memorizza in un array di struct VOPT i
parametri incontrati sulla command line, per la sintassi
della quale si veda storeopt(). La parseopt() invoca
storeopt() finché tutte i parametri della command line
sono stati scanditi (opzionalmente testati) e memorizzati
nell'array. Alloca automaticamente memoria per l'array,
che al termine contiene una struct OPT per ogni parametro.
RESTITUISCE NULL in caso di errore di allocazione.
SORGENTE parsopll.c
NOTE I campi della prima struct OPT dell'array hanno
significati particolari: il campo opt contiene l'indice
del (elemento dell'array corrispondente al) primo
parametro non-opzione nella command line, se ve ne sono;
il campo arg contiene argv[0]; il campo val contiene il
numero totale di argomenti non-opzione nella command line.
Ancora, il campo opt delle struct OPT relative a
parametri non-opzione sono valorizzati così: 0 per il
primo trovato, 1 per il secondo, etc..
*----------------------------------------------------------------------------*/
struct OPT *cdecl parseopt(int argc,char **argv,char *optionS,char sw,
char *illegalS,char *errorS,struct VOPT valfuncs[])
{
struct OPT *cmd = NULL, *tmp = NULL;
int no, i, fl, carg;
char option;
extern int optind;
if(!(cmd = (struct OPT *)realloc(cmd,sizeof(struct OPT))))
return(NULL);
optind = 1;
for(no = 1;(carg = storeopt(argc,argv,optionS,sw,cmd,illegalS,errorS)) > 0;
no++) {
if(!(tmp = (struct OPT *)realloc(cmd,(no+1)*sizeof(struct OPT)))) {
optind = 0;
return(NULL);
}
cmd = tmp;
(tmp += no)->opt = cmd->opt;
tmp->arg = (*cmd->arg == ':') ? cmd->arg + 1 : cmd->arg;
option = (!(tmp->val = cmd->val)) ? tmp->opt : ERRCHAR;
for(i = 0; (valfuncs+i)->opt; i++)
if((valfuncs+i)->opt == option)
if((valfuncs+i)->fun)
tmp->val = (*((valfuncs+i)->fun))(tmp,no);
}
cmd->opt = no;
cmd->arg = argv[0];
cmd->val = 0;
for(i = 0; (valfuncs+i)->opt; i++);
for(fl = 0, carg = -carg; carg < argc; carg++) {
if(!(tmp = (struct OPT *)realloc(cmd,(no+1)*sizeof(struct OPT))))
free(cmd);
cmd = tmp;
(tmp += no++)->opt = (char)cmd->val++;
tmp->arg = (*argv[carg] == sw && !fl) ? fl++, argv[carg] + 1 : argv[carg];
tmp->val = ((valfuncs+i)->fun) ? (*(valfuncs+i)->fun)(tmp,carg) : 0;
}
optind = 0;
return(cmd);
}
/*----------------------------------------------------------------------------*
parseoptions() Analizza i parametri della commnad line
SINTASSI int cdecl parseoptions(int argc,char **argv,
char *optionS,struct VOPT *valfuncs);
INCLUDE parsop.c
PARAMETRI argc numero di parametri sulla command line + 1.
E' generalmente argc parametro di main().
argv array di puntatori ai parametri della
command line. E' generalmente argv parametro
di main().
optionS puntatore alla stringa contenente tutti i
caratteri opazione riconosciuti dal
programma.
valfuncs puntatore ad un array di struct VOPT
(template definito in parsopt.h). L'array ha
un elemento per ogni opzione che si desidera
testare o convalidare. Ogni elemento è una
struct VOPT, la quale ha due campi: il primo
(char opt) contiene il carattere-opzione; il
secondo (int (*fun)(struct OPT *,int))
contiene il puntatore alla funzione che deve
essere invocata per testare l'opzione. Tale
funzione deve essere di tipo int ed
accettare due parametri, un puntatore a
struct OPT (template in parsopt.h) e un
int). Il primo punta alla struttura
valorizzata da storeopt() estraendo
l'opzione dalla command line, il secondo
rappresenta la posizione dell'opzione nella
command line. L'array DEVE avere, quale
ultimo elemento, una struct VOPT in cui il
campo opt è NULL: la funzione puntata dal
campo fun viene invocata per ciascun
parametro non-opzione incontrato sulla
command line. Inoltre, se il campo opt di
uno qualunque degli elementi dell'array
contiene il carattere ERRCHAR (parsopt.h)
la funzione puntata dal corrispondente campo
fun viene invocata quando l'opzione
restituita da storeopt() è sconosciuta o,
comunque, in caso di errore. Vedere
storeopt() circa la struct OPT.
SCOPO Analizza la command line e ne memorizza i parametri in un
array di struct OPT dopo averli (opzionalmente) testati.
Vedere storeopt() e parseopt(). Invoca parseopt() dopo
avere valorizzato il parametro sw con lo switch character
di default del DOS (getswitch()), illegalS con la stringa
"Illegal option" e errorS con la stringa "Unknown option".
RESTITUISCE NULL in caso di errore di allocazione.
SORGENTE parsopll.c
NOTE I campi della prima struct OPT dell'array hanno
significati particolari: il campo opt contiene l'indice
del (elemento dell'array corrispondente al) primo
parametro non-opzione nella command line, se ve ne sono;
il campo arg contiene argv[0]; il campo val contiene il
numero totale di argomenti non-opzione nella command line.
Ancora, il campo opt delle struct OPT relative a
parametri non-opzione sono valorizzati così: 0 per il
primo trovato, 1 per il secondo, etc..
*----------------------------------------------------------------------------*/
struct OPT *cdecl parseoptions(int argc,char **argv,char *optionS,
struct VOPT valfuncs[])
{
static char *illegalS = ILLEG_S;
static char *errorS = ERROR_S;
char sw;
return(((sw = (char)getswitch()) < 0) ? NULL :
parseopt(argc,argv,optionS,sw,illegalS,errorS,valfuncs));
}
/*----------------------------------------------------------------------------*
setswitch() Imposta lo switch character di default per il DOS
SINTASSI int cdecl setswitch(char sw);
INCLUDE parsopt.h
PARAMETRI sw il nuovo switch character di default del
DOS.
SCOPO Imposta il nuovo switch character di default del DOS. Per
sapere semplicemente qual è lo switch character attuale è
possibile usare getswitch().
RESTITUISCE il vecchio switch character, oppure, in caso di errore:
-1 funzione non supportata dal DOS (__IOerror() setta
errno e doserrno).
SORGENTE setdossw.c
NOTE Nessuna
*----------------------------------------------------------------------------*/
int cdecl setswitch(char sw)
{
asm {
mov ax,0x3700;
int 0x21;
cmp al,0xFF;
je notsupported;
push dx;
mov ax,0x3701;
mov dl,byte ptr sw;
int 0x21;
pop dx;
cmp al,0xFF;
je notsupported;
mov al,dl;
xor ah,ah;
jmp endfunc;
}
notsupported:
_AX = __IOerror(EINVFNC);
endfunc:
return(_AX);
}
/*----------------------------------------------------------------------------*
storeopt() Memorizza in struct gli argomenti della cmd line
SINTASSI int cdecl storeopt(int argc,char **argv,char *optionS,
char sw,struct OPT *cmd,char *illegalS,
char *errorS);
INCLUDE parsopt.h
PARAMETRI argc numero di parametri sulla command line + 1.
E', solitamente, argc parametro di main().
argv array di puntatori ai parametri nella
command line. E', solitamente, argv
parametro di main().
optionS puntatore alla stringa contenente tutti
caratteri-opzione riconosciuti dal
programma.
sw lo switch character.
cmd puntatore alla struct OPT (template in
parsopt.h) nella quale i dati relativi
all'opzione correntemente processata devono
essere memorizzati. Detta struct OPT è uno
delgi elementi dell'array allocato da
parseopt(). Una struct OPT è composta di tre
elementi: il primo (char opt) conterrà il
carattere-opzione; il secondo (char *arg)
punterà all'argomento dell'opzione (NULL se
l'opzione non accetta argomenti); il terzo
(int val) varrà normalmente 0: in caso di
errore (opzione sconosciuta o digitata in
modo scorretto o con argomento non valido)
sarà posto a -1. Esso è inoltre utilizzato
per memorizzare il valore restituito dalla
funzione di validazione dell'opzione
invocata da parseopt().
illegalS puntatore alla stringa usata come argomento
del carattere due punti (:) quando
utilizzato come opzione (illecita) nella
command line.
errorS puntatore alla stringa usata come argomento
dei caratteri-opzione non presenti in
optionS.
SCOPO memorizza in una struttura le opzioni presenti nella
command line. La sintassi, molto vicina a quella adottata
come standard nei sistemi Unix, è la seguente:
option : sw optLetter argLetter argument
dove
- sw è lo switch character
- non ci sono spazi tra lo switch character e ogni
optLetter o argLetter.
- optLetter e argLetter non sono segni di
punteggiatura.
- optLetter e argLetter devono comparire in optionS.
- argLetter, se presenti, devono essere seguite in
optionS da ':'.
- argument è una stringa che termina con uno spazio e
può essere preceduta da uno spazio. Può includere
lo switch character.
- maiuscole e minuscole non sono equivalenti.
Sulla command line possono comparire più clusters (gruppi)
di opzioni, ciascuno dei quali è introdotto dallo switch.
Tutti i clusters di pozioni devono comparire prima dei
parametri non-opzione (qualunque cosa non introdotta dallo
switch, ad eccezione delle stringhe argomenti di opzioni).
Una argLetter o optLetter può comparire più volte: è
compito del programmatore scegliere se ciò vada
considerato errore.
La stringa optionS consente il riconoscimento delle
optLetter e argLetter valide. In essa ogni argLetter è
seguita dai due punti (:). La storeopt() restituisce la
optLetter o argLetter processata; un valore minore di zero
se non vi sono più opzioni sulla command line.
Lo switch isolato tra spazi è un errore.
Due switch characters consecutivi (ad es.: -- o //)
vengono considerati il primo parametro non-opzione, il
primo dei due switch è rimosso e storeopt() restituisce un
valore negativo. Se vengono successivamente incontrate
altre coppie di switch characters sono lasciate immutate.
Pertanto tale combinazione può essere utilizzata se il
primo parametro non-opzione inizia con lo switch. Es.: se
PROG è il nome del programma, A è un'opzione valida, -5 è
il primo argomento, --ABC-- è il secondo, -4 il terzo e -
è lo switch, affinché la command line sia interpretata
correttamente occorrerà scriverla come segue:
PROG -A --5 --ABC-- -4
La optind e' inizialmente 1 e rappresenta sempre l'indice
del prossimo argomento di argv[], che storeopt() non ha
ancora analizzato. Se e' utilizzato SWSW allora optind e'
incrementata al successivo argomento prima che getopt()
restituisca il suo valore cambiato di segno (fine opzioni)
Il carattere due punti (:) può separare una argLetter dal
suo argomento sulla command line: esso viene ignorato. Se
l'argomento inizia con il due punti, esso va ripetuto.
Esempio:
-T:4 ---> argLetter = T, argomento = 4
-T::4 ---> argLetter = T, argomento = :4
Se è incontrata una lettera non inclusa in optionS, essa è
comunque restituita da storeopt(), ma nel campo val della
struct OPT viene memorizzato un valore negativo e non 0.
Esempio: se il DOS switch è '/' (DOS default) e optionS è
"A:F:PuU:wXZ:" allora 'P', 'u', 'w', e 'X' sono optLetter,
mentre 'A', 'F', 'U', 'Z' sono argLetter. Una command line
può essere:
PROG /uPFPi /X /A L /f UnFile AltraStringa
dove:
- 'u' e 'P' sono restituite come opzioni.
- 'F' è restituita con "Pi" come proprio argomento.
- 'X' è un'altra opzione.
- 'A' è restituita con "L" come argomento.
- 'f' non è presente in optionS, pertanto è
restituita memorizzando -1 nel campo val della
struct OPT. Essa è testata dalla funzione puntata
dal campo fun della struct VOPT che ha il carattere
ERRCHAR nel campo opt (se tale struct è definita
nell'array).
- "UnFile" non è un'opzione e viene testata con la
funzione puntata dall'elemento fun dell'ultima
struct VOPT dell'array.
- idem dicasi per "AltraStringa".
RESTITUISCE L'opzione processata, anche se non presente in optionS: in
questo caso il campo val della struct OPT è negativo;
esso, cambiato di segno, rappresenta l'indice
dell'elemento di argv[] successivo a quello attualmente
processato.
SORGENTE storeopt.c
NOTE I campi della prima struct OPT nell'array di strutture OPT
hanno un significato speciale (essi sono valorizzati da
parseopt() o parseoptions(), non da storeopt()). Vedere
parseopt() o parseoptions() per maggiore dettaglio.
-----------------------------------------------------------------------------*/
int cdecl storeopt(int argc,char **argv,char *optionS,char sw,struct OPT *cmd,
char *illegalS,char *errorS)
{
extern int optind; // numero della prossima opzione. Inizializzata a 1 da
static char *letP; // parseopt() in entrata e da essa riazzerata in uscita
char *optP;
while(argc > optind) { //while e' usato per evitare una goto; non e' un vero loop
cmd->val = 0;
if(!letP) {
if((!(letP = argv[optind])) || (*letP++ != sw))
break;
if(*letP == sw)
break;
}
if(!(cmd->opt = *letP++)) {
if(argv[++optind]) {
letP = NULL;
continue;
}
break;
}
if(cmd->opt == ':') {
cmd->arg = illegalS;
return(gopError(cmd));
}
if(!(optP = strchr(optionS,cmd->opt))) {
cmd->arg = errorS;
return(gopError(cmd));
}
if(*(optP+1) == ':') {
optind++;
if(!(*letP)) {
if (argc <= optind)
return(gopError(cmd));
letP = argv[optind++];
}
cmd->arg = letP;
letP = NULL;
}
else {
if(!(*letP)) {
optind++;
letP = NULL;
}
cmd->arg = NULL;
}
return((int)cmd->opt);
}
cmd->arg = letP = NULL;
return((int)(cmd->opt = -optind));
}