Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/refer/bib2ref.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>

typedef struct Bibent Bibent;

enum {
	Nfields = 100,
	Ntoks = 256,
};

#define Skipchars "{\"}"

struct Bibent {
	int	nfields;
	char*	tag[Nfields];
	char*	val[Nfields];
};

static char*	lastln;

static char*
eatcomment(char* ln)
{
	char*	p;
	char*	sp;
	if (ln == nil)
		return nil;
	p = strchr(ln, '%');
	if (p)
		*p = 0;
	for(sp = ln; sp && *sp && (*sp == ' '||*sp == '\t'); sp++)
		;
	if (sp != ln){
		sp = strdup(sp);
		free(ln);
		return sp;
	}
	return ln;
}

static char*
getln(Biobuf* bin)
{
	char*	ln;

	if (lastln){
		ln = lastln;
		lastln = nil;
	} else
		ln = eatcomment(Brdstr(bin, '\n', 1));
	return ln;
}

static void
ungetln(char* ln)
{
	lastln = ln;
}

static int
skiptobib(Biobuf* bin)
{
	char*	ln;

	while(ln = getln(bin)){
		if (strchr(ln, '@'))
			break;
		free(ln);
	}
	if (ln != nil){
		ungetln(ln);
		return 1;
	}
	return 0;
	
}

enum {
	Author = 0,
};

static struct {
	char*	bib;
	char*	ref;
} tags[] = {
	"author",	"%A",
	"title",	"%T",
	"journal",	"%J",
	"month",		"%D",
	"year",		"%Y",
	"volume",	"%V",
	"number",	"%N",
	"pages",	"%P",
	"keyword",	"%K",
	"booktitle",	"%B",
	"comment",	"#",
	"address",	"%C",
	"date",		"%D",
	"organization",	"%I",
	"publisher",	"%I",
	"institution",	"%I",
	"school",	"%I",
	"abstract",	"#",
	"key",		"%K",
};

static int
tagid(char* tname)
{
	int	i;

	for (i = 0; i < nelem(tags); i++)
		if (strcmp(tags[i].bib, tname) == 0)
			return i;
	return -1;
}

static void
printbibent(Bibent* be)
{
	int	i, t;
	char*	a;
	char*	s;

	for(i = 0; i < be->nfields; i++){
		t = tagid(be->tag[i]);
		switch(t){
		case Author:
			a = s = be->val[i];
			while(s && *s){
				s = strstr(a, " and ");
				if (s){
					*s = 0;
					s+=5;
					while(*s && (*s == ' ' || *s == '\t'))
						s++;
				}
				print("%s %s\n", tags[Author].ref, a);
				a = s;
			}
			break;
		default:
			if (t < 0)
				print("#%s:\t%s\n", be->tag[i], be->val[i]);
			else
				print("%s %s\n", tags[t].ref, be->val[i]);
		}
	}
	print("\n");
}

static void
freebibent(Bibent* be)
{
	int	i;
	for (i = 0; i < be->nfields; i++){
		free(be->tag[i]);
		free(be->val[i]);
	}
	free(be);
}

static char*
cleanbibval(char* old)
{
	char*	n;
	char*	np;
	char*	op;

	if (!old)
		return strdup("");
	if (*old == 0)
		return old;
	op = old;
	n = malloc(strlen(old)+1);
	for(np = n; *old; old++){
		if (strchr(Skipchars, *old))
			continue;
		*np++ = *old;
	}
	*np = 0;
	while(np > n && (np[-1] == ' ' || np[-1] == '\t'))
		*--np = 0;
	if (np > n && np[-1] == ',')
		*--np = 0;
	free(op);
	return n;
}

static int
readbibtag(Biobuf* bin, Bibent* be)
{
	char*	eq;
	char*	t;
	char*	ln;
	char*	s;
	while(ln = getln(bin)){
		if (strchr(ln, '@')){
			ungetln(ln);
			return 0;
		}
		eq = strchr(ln, '=');
		if (!eq){
			free(ln);	// skip down to next tag
			continue;	// (a comment?)
		}
		for (t = ln; *t && (*t == ' ' || *t == '\t'); t++)
			;
		*eq++ = 0;
		while(*eq && (*eq == ' ' || *eq == '\t'))
			eq++;
		s = strchr(t, ' ');
		if (s)
			*s = 0;
		s = strchr(t, '\t');
		if (s)
			*s = 0;
		for (s = t; *s; s++)
			*s = tolower(*s);
		be->tag[be->nfields] = strdup(t);
		be->val[be->nfields] = strdup(eq);
		be->nfields++;
		free(ln);
		return 1;
	}
	return 0;
}

static int
readbibfield(Biobuf* bin, Bibent* be)
{
	int	fid;
	char*	nf;
	char*	ln;

	fid = be->nfields;
	if (!readbibtag(bin, be))
		return 0;
	while(ln = getln(bin)){
		if (strchr(ln, '@') || strchr(ln, '=')){
			ungetln(ln);
			goto done;
		}
		nf = smprint("%s %s", be->val[fid], ln);
		free(be->val[fid]);
		free(ln);
		be->val[fid] = nf;
	}
done:
	be->val[fid] = cleanbibval(be->val[fid]);
	return 1;
}

static Bibent*
readbibentry(Biobuf* bin, Bibent* be)
{
	char*	ln;

	ln = getln(bin);
	if (ln == nil || !strchr(ln, '@')){
		freebibent(be);
		return nil;
	}
	while(readbibfield(bin, be))
		;
	return be;
}

static Bibent*
readbibent(Biobuf* bin)
{
	Bibent* be;

	be = malloc(sizeof(Bibent));
	memset(be, 0, sizeof(be));

	if (!skiptobib(bin))
		goto fail;	// no more entries
	be = readbibentry(bin, be);
	return be;
fail:
	freebibent(be);
	return nil;
}

static void
readbibfile(Biobuf* bin)
{
	Bibent*	be;

	while(be = readbibent(bin)){
		printbibent(be);
		freebibent(be);
	}
}

void
main(int argc, char*argv[])
{
	Biobuf*	bin;
	Biobuf	bsin;

	ARGBEGIN{
	default:
		fprint(2, "usage: %s file...\n", argv0);
		exits("usage");
	} ARGEND;
	if (argc == 0){
		Binit(&bsin, 0, OREAD);
		readbibfile(&bsin);
		Bterm(&bsin);
	} else {
		for(; argc--; argv++){
			if((bin = Bopen(*argv, OREAD)) == nil)
				sysfatal("%s cannot open - %r\n", *argv);
			readbibfile(bin);
			Bterm(bin);
		}
	}
	exits(nil);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].