/******************************************************************* Copyright (c) 1996 by the University of Southern California All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation in source and binary forms for any purpose and without fee is hereby granted, provided that both the above copyright notice and this permission notice appear in all copies. and that any documentation, advertising materials, and other materials related to such distribution and use acknowledge that the software was developed in part by the University of Southern California, Information Sciences Institute. The name of the University may not be used to endorse or promote products derived from this software without specific prior written permission. THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about the suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Other copyrights might apply to parts of this software and are so noted when applicable. ********************************************************************/ #include #include #include #include #include #include #include "config.h" #ifdef STANDARD_C_LIBRARY # include # include /* for offsetof */ #else # include # include #endif #include #include #include #include #include "rsvp_types.h" #include "rsvp_socks.h" #include "Pm_parse.h" #ifdef INCLUDE_SYSTEM_H #include "system.h" #endif int tolower(int); int strcasecmp(); /* * Value list: output of parse machine */ net_addr Pm_addrs[20]; u_int32_t Pm_val[20]; int Pm_vi; /* Value index: next value entry is * Pm_val[Pm_vi] */ #define val0 Pm_val[0] #define val1 Pm_val[1] #define val2 Pm_val[2] #define val3 Pm_val[3] char *Pm_Class_names[] = {"End", "Show", "Op", "NotOp", "Is", "IsNot", "File", "NotFile", "Set", "Action", "Label", "TRV"}; char *Pm_Op_names[] = {"none", "Integer", "cString", "Char", "Flag", "Host", "EOL", "WhSp"}; char *Result_name[] = {"ERR", "NO", "OK"}; #define ERR_printf(x) fprintf(stderr, (x)) #define ERR_printf2(x, y) fprintf(stderr, (x), (y)) #define ERR_printf3(x, y, z) fprintf(stderr, (x), (y), (z)) void Pm_print(int, Pm_inst *), Pm_list(Pm_inst *), Pm_print_vals(int); #define SkipWhSp {while (isspace(*Pm_cp)) Pm_cp++ ;} /* Parse Machine. Given address of program array, start recognition * sequence whose index is in transfer vector at offset PC_base. * Returns OK, NO, or ERR. May recurse. */ int Parse_machine(Pm_inst *Pm_program, int PC_base) { int i,Pm_PC; Pm_inst *ip, *tip; int testfor, result; u_int32_t val; int save_vi, first_vi; char *tcp, *fcp, *save_cp; char tbuf[256]; int L, found; FILE *infp; net_addr addr; /* PC_base actually points to Transfer Vector entry in * bottom of memory. Check that it is OK, then branch * to actual start of recognition sequence. */ tip = Pm_program + PC_base; if (PC_base <= 0 || tip->Pmi_class != PmC_TRV) { printf("Pm: Bad locn %d\n", PC_base); return(ERR); } Pm_PC = PC_base = tip->Pmi_next; first_vi = Pm_vi; while (1) { save_cp = Pm_cp; save_vi = Pm_vi; /* Fetch: */ ip = Pm_program + Pm_PC++; if (Pm_debug) { Pm_print(Pm_PC-1, ip); printf("SCAN: %s\n", Pm_cp); } /* Execute: */ testfor = OK; result = NO; switch (ip->Pmi_class) { case PmC_END: return(OK); case PmC_SHOW: if (ip->Pmi_parm) ERR_printf2("%s\n", ip->Pmi_parm); result = OK; break; case PmC_NOT_SUB: testfor = NO; case PmC_SUB: /* Execute subroutine, and go to next if * does/does not succeed. Call parse machine * recursively. */ result = Parse_machine(Pm_program, ip->Pmi_op); /* * If recognition failed, restore scan pointer * and value list pointer. */ if (result != OK) { Pm_cp = save_cp; Pm_vi = save_vi; } if (result == testfor && ip->Pmi_parm) ERR_printf2("%s\n", ip->Pmi_parm); if (Pm_debug) printf("\n"); break; case PmC_ACTION: /* Execute semantic subroutine, and branch. */ if (Pm_debug) { printf("\nAction %d (%d) vi=%d\n", ip->Pmi_op, (int)ip->Pmi_parm, first_vi); Pm_print_vals(first_vi); } result = Pm_Action(ip->Pmi_op, first_vi, (int)ip->Pmi_parm); break; case PmC_SET: /* Create literal value and append to values list. */ result = OK; val = (int)ip->Pmi_parm; Append_Val(val); break; case PmC_NOT_FILE: testfor = NO; case PmC_FILE: /* Look up in specified file, and * if found, take the rest of the line of file * as input and recursively parse using specified * labelled rule. Keyword is alphanumeric and dots. */ SkipWhSp; /* Skip White Space */ fcp = Pm_cp; while (isalnum(*Pm_cp) || *Pm_cp == '.') Pm_cp++; if (Pm_cp == fcp) break; /* Would be nicer to build in-memory copy of file... */ infp = fopen(ip->Pmi_parm, "r"); if (!infp) break; found = 0; while (fgets(tbuf, sizeof(tbuf), infp)) { char *cp1 = fcp, *cp2 = tbuf; while(tolower(*cp1++) == tolower(*cp2++)) if (cp1 == Pm_cp) break; if (cp1 != Pm_cp || !isspace(*cp2)) continue; /* Found match */ fcp = cp2; found = 1; break; } if (!found) break; save_cp = Pm_cp; Pm_cp = fcp; result = Parse_machine(Pm_program, ip->Pmi_op); Pm_cp = save_cp; if (result != OK) Pm_vi = save_vi; break; case PmC_NOT_OP: testfor = NO; case PmC_OP: /* Execute built-in parse operation, and set * result to OK/NO/ERR. */ switch (ip->Pmi_op) { case PmO_cString: /* Scan for case-independent match * to specified string. */ SkipWhSp; /* Skip White Space */ strncpy(tbuf, Pm_cp, L = strlen(ip->Pmi_parm)); tbuf[L] = '\0'; if (!strcasecmp(tbuf, ip->Pmi_parm)) { Pm_cp += L; result = OK; } break; case PmO_Integer: /* Scan for integer, and if one is * found, append to value list. Suffixes * K (1000) and M (10**6) are allowed. * Parm field is string to be displayed if * result is as requested. */ SkipWhSp; /* Skip White Space */ if (isdigit(*Pm_cp)) { val = 0; while (isdigit(*Pm_cp)) { val = 10*val + *Pm_cp++ - '0'; } if (tolower(*Pm_cp) == 'k') { val *= 1000; Pm_cp++; } else if (tolower(*Pm_cp) == 'm') { val *= 1000000; Pm_cp++; } Append_Val(val); result = OK; } if (result == testfor && ip->Pmi_parm) ERR_printf2("%s\n", ip->Pmi_parm); break; case PmO_Flag: /* Scan for any single char in given * string, and if one is found, append * its index to the value list. */ case PmO_Char: /* Scan for any single char in given * string but value list unchanged. */ SkipWhSp; /* Skip White Space */ for (tcp = ip->Pmi_parm; *tcp; tcp++) { if (*tcp == *Pm_cp) { result = OK; Pm_cp++; break; } } if (result == OK && ip->Pmi_op == PmO_Flag) Append_Val(tcp - ip->Pmi_parm); break; case PmO_Host: SkipWhSp; /* Skip White Space */ if (!(isalnum(*Pm_cp) || *Pm_cp == ':')) goto Nohost; fcp = Pm_cp; i = 0; while (isalnum(*Pm_cp) || *Pm_cp == '.' || *Pm_cp == '-' || *Pm_cp == ':' ) { if (!isdigit(*Pm_cp)) i = 1; Pm_cp++; } if (i == 0) goto Nohost; strncpy(tbuf, fcp, L = Pm_cp - fcp); tbuf[L] = '\0'; if (!net_addr_ascii(&addr,tbuf)) { ERR_printf2("Unknown host %s\n", tbuf); result = ERR; break; } result = OK; Append_Address(addr); Nohost: if (result == testfor && ip->Pmi_parm) ERR_printf2("%s\n", ip->Pmi_parm); break; case PmO_EOL: SkipWhSp; /* Skip White Space */ if (*Pm_cp == '\0') result = OK; if (result == testfor && ip->Pmi_parm) ERR_printf2("%s\n", ip->Pmi_parm); break; case PmO_WhSp: if (isspace(*Pm_cp)) { while (isspace(*Pm_cp)) Pm_cp++; result = OK; } if (result == testfor && ip->Pmi_parm) ERR_printf2("%s\n", ip->Pmi_parm); break; default: ERR_printf3("?? op %d for class %d\n", ip->Pmi_op, ip->Pmi_class); result = ERR; break; } /* * If recognition failed, restore scan pointer. */ if (result != OK) Pm_cp = save_cp; break; default: ERR_printf2("Unknown class %d\n", ip->Pmi_class); return(ERR); } if (Pm_debug) printf("RESULT: %s\n\n", Result_name[result+Pm_Ret+3]); if (result == ERR) return ERR; else if (result == testfor) { if (ip->Pmi_next <= (OK)) return(ip->Pmi_next); Pm_PC += ip->Pmi_next - 1; } } } int Pm_Init(Pm_inst *Pm_mem) { Pm_inst *ip, *ipd; int i, N, L; N = L = 0; for (ip = Pm_mem; ; ip++, N++) { if (ip->Pmi_class == PmC_LABEL) { if (ip->Pmi_next == 0) break; L = (L > ip->Pmi_next)? L:ip->Pmi_next; } } L++; ipd = ip + L; while (ip >= Pm_mem) { *ipd-- = *ip--; } ipd = Pm_mem; for (i=0; i < L; i++, ipd++) { memset((char *)ipd, 0, sizeof(Pm_inst)); ipd->Pmi_class = PmC_TRV; } for (ip = Pm_mem + L, N = L; ; ip++, N++) { if (ip->Pmi_class == PmC_LABEL) { if (ip->Pmi_next == 0) break; (Pm_mem+ip->Pmi_next)->Pmi_next = N + 1; } } return(1); } #define print_parm (ip->Pmi_parm)? ip->Pmi_parm : "(null)" void Pm_print(int Pm_PC, Pm_inst *ip) { char Next[8]; Pm_inst *tip; if (ip->Pmi_next <= OK) sprintf(Next, "%s", Result_name[ip->Pmi_next+Pm_Ret+3]); else sprintf(Next, "%d", ip->Pmi_next); switch(ip->Pmi_class) { case PmC_OP: printf("Pm: %4d: %8s \"%s\" -> %6s\n", Pm_PC, Pm_Op_names[ip->Pmi_op], print_parm, Next); break; case PmC_NOT_OP: printf("Pm: %4d: NOT %8s \"%s\" ->%6s\n", Pm_PC, Pm_Op_names[ip->Pmi_op], print_parm, Next); break; case PmC_ACTION: printf("Pm: %4d: Action %d (%d) ->%6s\n", Pm_PC, ip->Pmi_op, (int) ip->Pmi_parm, Next); return; case PmC_SET: printf("Pm: %4d: Set =%d ->%6s\n", Pm_PC, (int) ip->Pmi_parm, Next); return; case PmC_SUB: case PmC_NOT_SUB: tip = (Pm_inst *)( (char *)ip - (Pm_PC - ip->Pmi_op)*sizeof(Pm_inst)); printf("Pm: %4d: %8s %d(#%d) %s ->%6s\n", Pm_PC, Pm_Class_names[ip->Pmi_class], tip->Pmi_next, ip->Pmi_op, print_parm, Next); break; default: printf("Pm: %4d: %8s %d ->%6s\n", Pm_PC, Pm_Class_names[ip->Pmi_class], ip->Pmi_op, Next); break; } } void Pm_list(Pm_inst *Pm_mem) { Pm_inst *ip; int pc = 0; for (ip = Pm_mem; ip->Pmi_class != PmC_END; ip++, pc++) Pm_print(pc, ip); } void Pm_print_vals(int first) { int i; printf("%d Vals: ", Pm_vi); for (i=0; i < Pm_vi; i++) printf("%s %8.8X ", (i == first)?"|>":"", (u_int32_t) Pm_val[i]); printf("\n\n"); }