#include #include "QF/dstring.h" #include "QF/quakeio.h" #include "QF/script.h" #include "QF/sys.h" #include "QF/va.h" #include "EntityClass.h" @implementation EntityClass static int parse_vector (script_t * script, vec3_t vec) { int r; if (!Script_GetToken (script, 0)) return 0; if (strcmp (script->token->str, "(")) return 0; r = sscanf (script->p, "%f %f %f)", &vec[0], &vec[1], &vec[2]); if (r != 3) return 0; while (strcmp (script->token->str, ")")) { if (!Script_GetToken (script, 0)) return 0; } return 1; } // the classname, color triple, and bounding box are parsed out of comments // A ? size means take the exact brush size. // // /*QUAKED (0 0 0) ? // /*QUAKED (0 0 0) (-8 -8 -8) (8 8 8) // // Flag names can follow the size description: // // /*QUAKED func_door (0 .5 .8) ? START_OPEN STONE_SOUND DOOR_DONT_LINK GOLD_KEY SILVER_KEY -initFromText:(const char *) text source:(const char *) filename { const char *t; size_t len; int i; script_t *script; [super init]; text += strlen ("/*QUAKED "); script = Script_New (); Script_Start (script, filename, text); // grab the name if (!Script_GetToken (script, 0)) return 0; if (!strcmp (script->token->str, "*/")) return 0; name = strdup (script->token->str); // grab the color if (!parse_vector (script, color)) return 0; // get the size if (!strcmp (script->token->str, "(")) { Script_UngetToken (script); if (!parse_vector (script, mins)) return 0; if (!parse_vector (script, maxs)) return 0; esize = esize_fixed; } else if (!strcmp (script->token->str, "?")) { // use the brushes esize = esize_model; } else { return 0; } // get the flags // any remaining words on the line are parm flags for (i = 0; i < MAX_FLAGS; i++) { if (!Script_TokenAvailable (script, 0)) break; Script_GetToken (script, 0); flagnames[i] = strdup (script->token->str); } while (Script_TokenAvailable (script, 0)) Script_GetToken (script, 0); // find the length until close comment for (t = script->p; t[0] && !(t[0] == '*' && t[1] == '/'); t++); // copy the comment block out len = t - text; comments = malloc (len + 1); memcpy (comments, text, len); comments[len] = 0; return self; } -(esize_t) esize { return esize; } -(char *) classname { return name; } -(float *) mins { return mins; } -(float *) maxs { return maxs; } -(float *) drawColor { return color; } -(char *) comments { return comments; } -(char *) flagName:(unsigned) flagnum { if (flagnum >= MAX_FLAGS) Sys_Error ("EntityClass flagName: bad number"); return flagnames[flagnum]; } @end //=========================================================================== @implementation EntityClassList /* ================= insertEC: ================= */ - (void) insertEC:ec { char *name; int i; name =[ec classname]; for (i = 0; i <[self count]; i++) { if (strcasecmp (name,[[self objectAtIndex:i] classname]) < 0) { [self insertObject: ec atIndex:i]; return; } } [self addObject:ec]; } /* ================= scanFile ================= */ -(void) scanFile:(char *) filename { int size, line; char *data; id cl; int i; char path[1024]; QFile *file; sprintf (path, "%s/%s", source_path, filename); file = Qopen (path, "rt"); if (!file) return; size = Qfilesize (file); data = malloc (size + 1); size = Qread (file, data, size); data[size] = 0; Qclose (file); line = 1; for (i = 0; i < size; i++) { if (!strncmp (data + i, "/*QUAKED", 8)) { cl =[[EntityClass alloc] initFromText:(data + i) source:va ("%s:%d", filename, line)]; if (cl) [self insertEC:cl]; } else if (data[i] == '\n') { line++; } } free (data); } /* ================= scanDirectory ================= */ -(void) scanDirectory { int count, i; struct dirent **namelist, *ent; [self removeAllObjects]; count = scandir (source_path, &namelist, NULL, NULL); for (i = 0; i < count; i++) { int len; ent = namelist[i]; len = strlen (ent->d_name); if (len <= 3) continue; if (!strcmp (ent->d_name + len - 3, ".qc")) [self scanFile:ent->d_name]; } } id entity_classes_i; -initForSourceDirectory:(char *) path { [super init]; source_path = path; [self scanDirectory]; entity_classes_i = self; nullclass =[[EntityClass alloc] initFromText: "/*QUAKED UNKNOWN_CLASS (0 0.5 0) ?*/" source:va ("%s:%d", __FILE__, __LINE__ - 1)]; return self; } -(id) classForName:(char *) name { int i; id o; for (i = 0; i <[self count]; i++) { o =[self objectAtIndex:i]; if (!strcmp (name,[o classname])) return o; } return nullclass; } @end