mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-12-03 17:42:40 +00:00
6d5e8922a5
I never liked the various hacks I had come up with for representing resource handles in Ruamoko. Structs with an int were awkward to test, pointers and ints could be modified, etc etc. The new @handle keyword (@ used to keep handle free for use) works just like struct, union and enum in syntax, but creates an opaque type suitable for a 32-bit handle. The backing type is a function so v6 progs can use it without (all the necessary opcodes exist) and no modifications were needed for type-checking in binary expressions, but only assignment and comparisons are supported, and (of course) nil. Tested using cbuf_t and QFile: seems to work as desired. I had considered 64-bit handles, but really, if more than 4G resource objects are needed, I'm not sure QF can handle the game. However, that limit is per resource manager, not total.
276 lines
5.9 KiB
R
276 lines
5.9 KiB
R
#include <hash.h>
|
|
#include <qfile.h>
|
|
#include <runtime.h>
|
|
#include <string.h>
|
|
#include <types.h>
|
|
#include <Array.h>
|
|
#include <AutoreleasePool.h>
|
|
#include <PropertyList.h>
|
|
|
|
#include "vkgen.h"
|
|
#include "vkstruct.h"
|
|
#include "vkfixedarray.h"
|
|
#include "vkenum.h"
|
|
|
|
static AutoreleasePool *autorelease_pool;
|
|
static void
|
|
arp_start (void)
|
|
{
|
|
autorelease_pool = [[AutoreleasePool alloc] init];
|
|
}
|
|
|
|
static void
|
|
arp_end (void)
|
|
{
|
|
[autorelease_pool release];
|
|
autorelease_pool = nil;
|
|
}
|
|
|
|
void printf (string fmt, ...) = #0;
|
|
|
|
void fprintf (QFile file, string format, ...)
|
|
{
|
|
Qputs (file, vsprintf (format, va_copy (@args)));
|
|
}
|
|
|
|
hashtab_t *available_types;
|
|
hashtab_t *processed_types;
|
|
Array *queue;
|
|
Array *output_types;
|
|
|
|
PLItem *parse;
|
|
QFile output_file;
|
|
QFile header_file;
|
|
|
|
qfot_type_encodings_t *encodings;
|
|
|
|
qfot_type_t *
|
|
next_type (qfot_type_t *type)
|
|
{
|
|
int size = type.size;
|
|
if (!size)
|
|
size = 4;
|
|
return (qfot_type_t *) ((int *) type + size);
|
|
}
|
|
|
|
int
|
|
type_is_null (qfot_type_t *type)
|
|
{
|
|
return type.size == 0;
|
|
}
|
|
|
|
void print_type (qfot_type_t *type)
|
|
{
|
|
//printf ("type: %p %d %d %s", type, type.meta, type.size, type.encoding);
|
|
switch (type.meta) {
|
|
case ty_basic:
|
|
//printf (" %d", type.type);
|
|
switch (type.type) {
|
|
case ev_ptr:
|
|
case ev_field:
|
|
//printf (" ");
|
|
print_type (type.fldptr.aux_type);
|
|
break;
|
|
case ev_func:
|
|
//printf (" %p %d\n", type.func.return_type,
|
|
// type.func.num_params);
|
|
default:
|
|
//printf ("\n");
|
|
break;
|
|
}
|
|
break;
|
|
case ty_struct:
|
|
case ty_union:
|
|
case ty_enum:
|
|
//printf (" %s %d\n", type.strct.tag, type.strct.num_fields);
|
|
break;
|
|
case ty_array:
|
|
//printf (" %p %d %d\n", type.array.type, type.array.base,
|
|
// type.array.size);
|
|
break;
|
|
case ty_class:
|
|
//printf (" %s\n", type.class);
|
|
break;
|
|
case ty_alias:
|
|
//printf (" %d %s ", type.alias.type, type.alias.name);
|
|
print_type (type.alias.aux_type);
|
|
break;
|
|
case ty_handle:
|
|
//printf (" %s\n", type.handle.tag);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
scan_types (void)
|
|
{
|
|
qfot_type_t *type;
|
|
|
|
for (type = encodings.types;
|
|
((int *)type - (int *) encodings.types) < encodings.size;
|
|
type = next_type (type)) {
|
|
if (type.size) {
|
|
string tag = str_mid(type.strct.tag, 4);
|
|
Type *avail_type = [Type fromType: type];
|
|
if (avail_type) {
|
|
if (!Hash_Find (available_types, [avail_type name])) {
|
|
//printf ("scan: %s %s\n", tag, [avail_type name]);
|
|
Hash_Add (available_types, avail_type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static string
|
|
get_string_key (void *str, void *unused)
|
|
{
|
|
return (string) str;
|
|
}
|
|
|
|
static string
|
|
get_object_key (void *obj, void *unused)
|
|
{
|
|
return [(id)obj name];
|
|
}
|
|
|
|
static void
|
|
free_object (void *obj, void *unused)
|
|
{
|
|
[(id)obj release];
|
|
}
|
|
|
|
void
|
|
usage (string name)
|
|
{
|
|
printf ("%s [plist file] [output file] [header file]\n", name);
|
|
}
|
|
|
|
int
|
|
main(int argc, string *argv)
|
|
{
|
|
int do_struct = 0;
|
|
int do_enum = 0;
|
|
string plist_filename;
|
|
QFile plist_file;
|
|
PLItem *plist;
|
|
PLItem *search;
|
|
PLItem *handles;
|
|
|
|
arp_start ();
|
|
|
|
if (argc != 4) {
|
|
usage (argv[0]);
|
|
return 1;
|
|
}
|
|
plist_filename = argv[1];
|
|
plist_file = Qopen (plist_filename, "rt");
|
|
if (!plist_file) {
|
|
printf ("could not open property list file: %s\n", plist_filename);
|
|
return 1;
|
|
}
|
|
plist = [[PLDictionary fromFile: plist_file] retain];
|
|
if (!plist) {
|
|
printf ("error parsing: %s\n", plist_filename);
|
|
return 1;
|
|
}
|
|
Qclose (plist_file);
|
|
if ([plist class] != [PLDictionary class]) {
|
|
printf ("%s not a dictionary\n", plist_filename);
|
|
return 1;
|
|
}
|
|
search = [[plist getObjectForKey: "search"] retain];
|
|
handles = [[plist getObjectForKey: "handles"] retain];
|
|
parse = [[plist getObjectForKey: "parse"] retain];
|
|
|
|
encodings = PR_FindGlobal (".type_encodings");
|
|
if (!encodings) {
|
|
printf ("Can't find encodings\n");
|
|
return 1;
|
|
}
|
|
queue = [[Array array] retain];
|
|
output_types = [[Array array] retain];
|
|
available_types = Hash_NewTable (127, get_object_key, free_object, nil);
|
|
processed_types = Hash_NewTable (127, get_string_key, nil, nil);
|
|
scan_types ();
|
|
|
|
for (int i = [search numObjects]; i-- > 0; ) {
|
|
PLString *str = (PLString *) [search getObjectAtIndex:i];
|
|
string search_name = [str string];
|
|
id obj = (id) Hash_Find (available_types, search_name);
|
|
obj = [obj resolveType];
|
|
//printf("obj: %d %s\n", obj, class_get_class_name([obj class]));
|
|
if (obj && ([obj class] == [Struct class]
|
|
|| [obj class] == [Enum class])) {
|
|
[obj addToQueue];
|
|
}
|
|
}
|
|
|
|
while ([queue count]) {
|
|
id obj = [queue objectAtIndex:0];
|
|
[queue removeObjectAtIndex:0];
|
|
if ([obj class] == [Struct class]) {
|
|
string name = [obj name];
|
|
if (name == "char" // char type faked via a struct
|
|
|| [[parse getObjectForKey:name] string] == "skip") {
|
|
continue;
|
|
}
|
|
[obj queueFieldTypes];
|
|
}
|
|
[output_types addObject:obj];
|
|
}
|
|
|
|
for (int i = 0; i < argc; i++) {
|
|
//printf ("vkgen %d %s\n", i, argv[i]);
|
|
}
|
|
|
|
arp_end ();
|
|
|
|
output_file = Qopen (argv[2], "wt");
|
|
header_file = Qopen (argv[3], "wt");
|
|
for (int i = [output_types count]; i-- > 0; ) {
|
|
id obj = [output_types objectAtIndex:i];
|
|
if ([obj name] == "VkStructureType") {
|
|
continue;
|
|
}
|
|
|
|
arp_start ();
|
|
[obj writeForward];
|
|
[obj initParse:[parse getObjectForKey:[obj name]]];
|
|
arp_end ();
|
|
}
|
|
for (int i = [output_types count]; i-- > 0; ) {
|
|
id obj = [output_types objectAtIndex:i];
|
|
if ([obj name] == "VkStructureType") {
|
|
continue;
|
|
}
|
|
|
|
arp_start ();
|
|
[obj writeTable];
|
|
arp_end ();
|
|
}
|
|
fprintf (output_file, "static void\n");
|
|
fprintf (output_file, "vkgen_init_symtabs (exprctx_t *context)\n");
|
|
fprintf (output_file, "{\n");
|
|
for (int i = [output_types count]; i-- > 0; ) {
|
|
id obj = [output_types objectAtIndex:i];
|
|
if ([obj name] == "VkStructureType") {
|
|
continue;
|
|
}
|
|
arp_start ();
|
|
[obj writeSymtabInit];
|
|
[obj writeSymtabEntry];
|
|
arp_end ();
|
|
}
|
|
fprintf (output_file, "}\n");
|
|
Qclose (output_file);
|
|
Qclose (header_file);
|
|
Hash_DelTable (available_types);
|
|
[plist release];
|
|
[search release];
|
|
[handles release];
|
|
[parse release];
|
|
[queue release];
|
|
[output_types release];
|
|
return 0;
|
|
}
|