/* container-metafile.m,
 *
 * This is an abstract container with some helper methods for
 * processing metafiles.
 */

#include <assert.h>
#include <ctype.h>
#include <zzip/zzip.h>
#include "container-metafile.h"
#include "seborrhea-debug.h"


#ifndef PATH_MAX
# define PATH_MAX		512
#endif


@implementation AbstractSebContainerWithMetafile
- (BOOL) openMetafile:(const char *)top_dir :(const char *)sub_dir WithDirList:(DirectoryList *)dirlist
{
    char metafn[PATH_MAX];
    assert(top_dir && sub_dir && dirlist);
    assert(not metafp);

    /* XXX: Should check if file exists, return YES if it doesn't, and
       NO if it couldn't open. */
    snprintf(metafn, sizeof metafn, "%s%s=meta", top_dir, sub_dir);
    metafp = [dirlist openFile:metafn];
    if (not metafp)
	return NO;

    SEBORRHEA_MESSAGE(stdout, "[%s] Reading %s\n", [[self class] name], metafn);
    return YES;
}

- (void) closeMetafile:(DirectoryList *)dirlist
{
    assert(dirlist);

    if (metafp) {
	[dirlist closeFile:metafp];
	metafp = NULL;
    }
}

- (BOOL) seekInFile:(void *)fp For:(const char *)seekee WithDirList:(DirectoryList *)dirlist
{
    int parentheses_depth = 0;
    assert(fp && seekee && dirlist);

    /* Go to the start. */
    if ([[dirlist class] isReal])	/* XXX */
	rewind(fp);
#ifndef NO_ZZIP
    else
	zzip_rewind(fp);
#endif

    if (not expect_char(fp, '('))
	return NO;

    do {
	Token *tok;
	parentheses_depth++;

	while ((tok = read_token(fp))) {
	    if ([tok isType:TOKEN_SYMBOL]) {
		if ((parentheses_depth == 1) &&
		    streq([tok getSymbol], seekee)) {
		    /* We found it! */
		    [tok free];
		    return YES;
		}
	    }
	    [tok free];
	}

	while (expect_char(fp, ')')) {
	    parentheses_depth--;

	    if (parentheses_depth < 0)
		goto exit_without_finding_seekee;
	}
    } while (expect_char(fp, '('));

 exit_without_finding_seekee:
    if (parentheses_depth != 0) {
	fprintf(stderr, "[%s:%s] Mismatching parentheses in meta/contents file (%d).\n",
		[[self class] name], [self name], parentheses_depth);
    }
    return NO;
}

- (int) readTokensNonParenthesisFrom:(void *)fp :(Token *[])argv :(unsigned int)max_args
{
    unsigned int argc = 0;
    assert(fp && argv);

    while ((argv[argc] = read_token(fp))) {
	argc++;

	if (argc >= max_args) {
	    fprintf(stderr, "[%s] Maximum number of tokens reached while reading arguments!\n",
		    [[self class] name]);
	    break;
	}
    }

    if (not expect_char(metafp, ')')) {
	while (argc > 0) {		/* Error!  Free arguments. */
	    argc--;
	    argv[argc] = [argv[argc] free];
	}

	return -1;
    }

    return argc;
}

- (BOOL) startLoadingSebumDirectory:(const char *)top_dir :(const char *)sub_dir WithDirList:(DirectoryList *)dirlist
{
    assert(top_dir && sub_dir && dirlist);
    SEBORRHEA_MESSAGE(stdout, "[%s] Opening %s%s\n", [[self class] name], top_dir, sub_dir);

    if ([[dirlist class] isReal])
	set_token_reader_stdio();
#ifndef NO_ZZIP
    else
	set_token_reader_zzpk();
#endif

    return YES;
}
@end
