#ifndef __REGEXP_H #include #endif #include // codici di ritorno della matche() #define regexp_MATCH_PATTERN (6) // pattern non valido #define regexp_MATCH_LITERAL (5) // il pattern non coincide su un carattere comune #define regexp_MATCH_RANGE (4) // il pattern non coincide in un costrutto [..] #define regexp_MATCH_ABORT (3) // il stringa da confrontare è terminata anticipatamente #define regexp_MATCH_END (2) // il pattern è terminato anticipatamente #define regexp_MATCH_VALID (1) // pattern e stringa coincidono // codici di ritorno della is_valid_pattern() #define regexp_PATTERN_VALID (0) // il pattern è valido #define regexp_PATTERN_ESC (-1) // è presente un escape aperto a fine pattern #define regexp_PATTERN_RANGE (-2) // c'è un range non chiuso all'interno di un costrutto [..] #define regexp_PATTERN_CLOSE (-3) // manca la parentesi di chiusura in un costrutto [..] #define regexp_PATTERN_EMPTY (-4) // c'è un costrutto vuoto // prototipi delle funzioni interne HIDDEN int matche(const char *pat, const char *str); // ritorna un codice della classe regexp_MATCH che indica se e in che modo pattern e stringa coincidono HIDDEN int matche_after_star(const char *pat, const char *str); // chiama ricorsivamente la matche() con i segmenti puri del pattern e della stringa HIDDEN bool is_pattern(const char *pat); // ritorna TRUE se la stringa è un pattern HIDDEN bool is_valid_pattern(const char *pat, int *err= NULL); // ritorna TRUE se la stringa è un pattern valido, indica un codice di ritorno della classe regexp_PATTERN nel secondo parametro HIDDEN bool is_pattern(const char *p) { while (*p) { switch (*p++) { case '?': case '*': case '[': case '\\': return TRUE; } } return FALSE; } HIDDEN bool is_valid_pattern(const char *p, int *error_type) { if (error_type != NULL) *error_type= regexp_PATTERN_VALID; // inizializzazione del tipo d'errore while (*p) { // ciclo all'interno del pattern fino a fine stringa switch(*p) { // determinazione del tipo di wild card nel pattern case '\\': // controllo dell'escape, non può essere a fine pattern if (!*++p) { if (error_type != NULL) *error_type= regexp_PATTERN_ESC; return FALSE; } p++; break; case '[': // controllo della costruzione del costrutto [..] p++; if (*p == ']') { // se il prossimo carattere è ']' il costrutto è vuoto if (error_type != NULL) *error_type= regexp_PATTERN_EMPTY; return FALSE; } if (!*p) { // se si è a fine stringa il costrutto non è chiuso if (error_type != NULL) *error_type= regexp_PATTERN_CLOSE; return FALSE; } while (*p != ']') { // ciclo fino a fine costrutto [..] if (*p == '\\') { // controllo per gli escape p++; if (!*p++) { // controllo che l'escape non sia a fine pattern if (error_type != NULL) *error_type= regexp_PATTERN_ESC; return FALSE; } } else p++; if (!*p) { // se si è a fine stringa il costrutto non è chiuso if (error_type != NULL) *error_type= regexp_PATTERN_CLOSE; return FALSE; } if (*p == '-') { // controllo di un eventuale range if (!*++p || *p == ']') { // deve esistere una fine del range if (error_type != NULL) *error_type= regexp_PATTERN_RANGE; return FALSE; } else { if (*p == '\\') p++; // controllo degli escape if (!*p++) { // controllo che l'escape non sia a fine pattern if (error_type != NULL) *error_type= regexp_PATTERN_ESC; return FALSE; } } } } break; case '*': // tutti gli altri caratteri sono elementi validi del pattern case '?': default: p++; // caratteri normali break; } } return TRUE; } HIDDEN int matche_after_star(const char *p, const char *t) { int match= 0; while (*p == '?' || *p == '*') { // salto degli eventuali '*' e '?' if (*p == '?') // salto di un carattere per ciascun '?' if (!*t++) return regexp_MATCH_ABORT; // se la stringa termina qui non c'è coincidenza p++; // posizionamento sul prossimo carattere del pattern } if (!*p) return regexp_MATCH_VALID; //se il pattern è concluso c'è coincidenza int nextp= *p; // prelevamento del prossimo carattere, normale o '[' if (nextp == '\\') { nextp= p[1]; if (!nextp) return regexp_MATCH_PATTERN; // se il pattern termina qui non è valido } do { // ciclo fino a conclusione di stringa o pattern if (nextp == *t || nextp == '[') match= matche(p, t); // è necessario che il carattere corrente del testo coincida con il carattere corrente del pattern, oppure che il pattern abbia un inizio di costrutto [..] if (!*t++) match= regexp_MATCH_ABORT; // se la stringa termina qui non c'è coincidenza } while (match != regexp_MATCH_VALID && match != regexp_MATCH_ABORT && match != regexp_MATCH_PATTERN); return match; // ritorno del risultato } HIDDEN int matche(const char *p, const char *t) { for (; *p; p++, t++) { if (!*t) // se si è alla fine della stringa, il confronto è concluso return (*p == '*' && *++p == '\0') ? regexp_MATCH_VALID : regexp_MATCH_ABORT; switch (*p) { // determina il tipo di wild card del pattern case '?': // carattere singolo, qualunque carattere coincide break; case '*': // sottostringa, coincide qualunque sequenza di caratteri return matche_after_star (p, t); case '[': { // costrutto [..], controllo di coincidenza per inclusione o esclusione su un solo carattere p++; // posizionamento all'inizio del range bool invert= FALSE; // controllo di inclusione o esclusione del costrutto if (*p == '!' || *p == '^') { invert= TRUE; p++; } if (*p == ']') // se si è su una chiusura di costrutto il pattern non è valido return regexp_MATCH_PATTERN; bool member_match= FALSE; bool loop= TRUE; while (loop) { char range_start, range_end; // inizio e fine del range corrente if (*p == ']') { // se si è alla fine del costrutto il ciclo si conclude loop= FALSE; continue; } if (*p == '\\') // controllo di coincidenza su un metacarattere, dopo un escape range_start= range_end= *++p; else range_start= range_end= *p; if (!*p) return regexp_MATCH_PATTERN; // se il pattern termina non è valido if (*++p == '-') { // controllo del segno di sottoinsieme range_end= *++p; // impostazione della fine del range if (range_end == '\0' || range_end == ']') return regexp_MATCH_PATTERN; // se il costrutto [..] o il pattern terminano qui allora il pattern non è valido if (range_end == '\\') { // la fine del range è un metacarattere range_end= *++p; if (!range_end) return regexp_MATCH_PATTERN; // se il pattern termina non è valido } p++; // posizionamento oltre il range } if (range_start < range_end) { // confronto del carattere corrente con il costrutto, controllo della sequenzialità degli estremi del range if (*t >= range_start && *t <= range_end) { member_match= TRUE; loop= FALSE; } } else { if (*t >= range_end && *t <= range_start) { member_match= TRUE; loop= FALSE; } } } if ((invert && member_match) || !(invert || member_match)) // controllo del risultato dell'ultimo confronto nel costrutto [..] return regexp_MATCH_RANGE; if (member_match) { // salto del resto del costrutto se non è esclusivo while (*p != ']') { if (!*p) return regexp_MATCH_PATTERN; // se si è a fine pattern il costrutto non è valido if (*p == '\\') { // salto di un confronto con un metacarattere p++; if (!*p) return regexp_MATCH_PATTERN; // se il pattern termina qui non è valido } p++; // posizionamento sul prossimo carattere del pattern } } break; } case '\\': // confronto con un metacarattere p++; // posizionamento sul carattere da confrontare if (!*p) return regexp_MATCH_PATTERN; // se il pattern termina qui non è valido default: // confronto con un carattere normale if (*p != *t) return regexp_MATCH_LITERAL; } } if (*t) return regexp_MATCH_END; // se la stringa non è conclusa non c'è coincidenza else return regexp_MATCH_VALID; } bool match(const char *pat, const char *str) { int err= matche(pat, str); return (err == regexp_MATCH_VALID); // ritorna TRUE se il pattern e la stringa coincidono }