Blob Blame Raw
/*
 * tl2rpm 0.0.1, TeX Live to RPM converter.
 * 
 * Copyright (C) 2009-2012 Jindrich Novy (jnovy@users.sf.net)
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#define _GNU_SOURCE
//#define PACKAGE_SOURCE
#define PACKAGE_DOCS
//#define MERGE_DOCS
//#define SRPMS
//#define SHORTEN_FILELISTS
//#define FEDORA_FONTS
#define UNPACK "xz"
#define REQ_POSTTRANS "Requires: "
#define REQ_POST_POSTUN "Requires(post,postun): "
#ifndef TL2010
//#  define CTAN_URL "ftp://ftp.ctex.org/mirrors/CTAN/systems/texlive/tlnet/archive/"
#  define CTAN_URL "http://ctan.sharelatex.com/tex-archive/systems/texlive/tlnet/archive/"
#else
#  define CTAN_URL ""
#endif
#ifdef DEBUG
#  define REDIR "\n"
#else
#  define REDIR " > /dev/null 2>&1\n"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "tl-oldpkgs.h"
char arch[] = "i386-linux";
char *m;
off_t size, pos;
typedef struct {
	char *token;
	int num;
	size_t s;
} match;
enum {CAT_COLLECTION, CAT_DOCUMENTATION, CAT_PACKAGE, CAT_SCHEME, CAT_TLCORE, CAT_CONTEXT};
match category[] = {
	{"Collection", CAT_COLLECTION},
	{"Documentation", CAT_DOCUMENTATION},
	{"Package", CAT_PACKAGE},
	{"Scheme", CAT_SCHEME},
	{"TLCore", CAT_TLCORE},
	{"ConTeXt", CAT_CONTEXT},
	{NULL, 0}
};
enum {
	LIC_GPL		= 1<<0,
	LIC_LPPL	= 1<<1,
	LIC_OTHER_FREE	= 1<<2,
	LIC_PD		= 1<<3,
	LIC_LGPL	= 1<<4,
	LIC_GFSL	= 1<<5,
	LIC_BSD		= 1<<6,
	LIC_GFL		= 1<<7,
	LIC_ARTISTIC2	= 1<<8,
	LIC_FDL		= 1<<9,
	LIC_COLLECTION	= 1<<10,
	LIC_OTHER	= 1<<11,
	LIC_OFL		= 1<<12,
	LIC_APACHE2	= 1<<13,
	LIC_NOINFO	= 1<<14,
	LIC_UNKNOWN	= 1<<15,
	LIC_KNUTH	= 1<<16,
	LIC_ARTISTIC	= 1<<17,
	LIC_NOSOURCE	= 1<<18,
	LIC_NOSELL	= 1<<19,
	LIC_NOCOMMERCIAL= 1<<20,
	LIC_GPL2	= 1<<21,
	LIC_GPL3	= 1<<22,
	LIC_LPPL12	= 1<<23,
	LIC_LPPL13	= 1<<24,
};
#define LIC_PROBLEMATIC (LIC_NOINFO | LIC_UNKNOWN | LIC_ARTISTIC | LIC_NOSOURCE | LIC_NOSELL | LIC_NOCOMMERCIAL | LIC_OTHER)
#define LIC_NOTALLOWED LIC_PROBLEMATIC
match license[] = {
	{"gpl3", LIC_GPL3},
	{"gpl2", LIC_GPL2},
	{"gpl", LIC_GPL},
	{"lppl1.3", LIC_LPPL13},
	{"lppl1.2", LIC_LPPL12},
	{"lppl1", LIC_LPPL},
	{"lppl", LIC_LPPL},
	{"other-free", LIC_OTHER_FREE},
	{"pd", LIC_PD},
	{"noinfo", LIC_NOINFO},
	{"lgpl2.1", LIC_LGPL},
	{"lgpl", LIC_LGPL},
	{"gfsl", LIC_GFSL},
	{"bsd", LIC_BSD},
	{"knuth", LIC_KNUTH},
	{"unknown", LIC_UNKNOWN},
	{"gfl", LIC_GFL},
	{"artistic2", LIC_ARTISTIC2},
	{"fdl", LIC_FDL},
	{"collection", LIC_COLLECTION},
	{"artistic", LIC_ARTISTIC},
	{"other-nonfree", LIC_OTHER},
	{"other", LIC_OTHER},
	{"ofl", LIC_OFL},
	{"apache2", LIC_APACHE2},
	{"nosource", LIC_NOSOURCE},
	{"nosell", LIC_NOSOURCE},
	{"nocommercial", LIC_NOCOMMERCIAL},
	{NULL, 0}
};
match spec_license[] = {
	{"GPL+", LIC_GPL},
	{"GPLv2+", LIC_GPL2},
	{"GPLv3+", LIC_GPL3},
	{"LPPL", LIC_LPPL},
	{"LPPL 1.2", LIC_LPPL12},
	{"LPPL 1.3", LIC_LPPL13},
	{"Freely redistributable without restriction", LIC_OTHER_FREE},
	{"Public Domain", LIC_PD},
	{"No Info", LIC_NOINFO},
	{"LGPLv2+", LIC_LGPL},
	{"GFSL", LIC_GFSL},
	{"BSD", LIC_BSD},
	{"Knuth", LIC_KNUTH},
	{"Unknown", LIC_UNKNOWN},
	{"LPPL", LIC_GFL},
	{"Artistic 2.0", LIC_ARTISTIC2},
	{"GFDL", LIC_FDL},
	{"Public Domain", LIC_COLLECTION},
	{"Artistic", LIC_ARTISTIC},
	{"Other", LIC_OTHER},
	{"OFL", LIC_OFL},
	{"ASL 2.0", LIC_APACHE2},
	{"No Source", LIC_NOSOURCE},
	{"No Sell", LIC_NOSOURCE},
	{"Non-commercial", LIC_NOCOMMERCIAL},
	{NULL, 0}
};
typedef struct pk {
	char *name;
	unsigned long namehash;
	int category;
	char *shortdesc;
	char **longdesc;
	int longdesc_lines;
	char **runf;
	int runfs;
	char **docf;
	int docfs;
	char **srcf;
	int srcfs;
	char **binf;
	int binfs;
	char *revision;
	char *catalogue_ctan;
	int catalogue_license;
	char *fedora_license;
	char *catalogue_date;
	char *catalogue_version;
	char **dep;
	struct pk **req;
	int reqs;
	char **file_req;
	int file_reqs;
	char **file_prov;
	int file_provs;
	char **exe;
	int exes;
	int reloc;
	int has_man;
	int has_info;
	int main_pkg_written;
	int any_pkg_written;
} package;
typedef struct {
	char *dir;
	unsigned long dirhash;
	char **pkg;
	unsigned long *pkghash;
	int *lic;
	int pkgs;
} dir_type;
dir_type *dir;
int dirs;
package *pkg;
int p = 0;
/* Packages to be ignored and not included */
char *pkg_blacklist[] = {
	"getafm",
	"psutils",
	"t1utils",
	"texworks",
	"xindy",	// dependency on clisp
	"asymptote",	// special build procedure, packaged separately
	"asymptote.i386-linux",
	"asymptote-by-example-zh-cn",
	"asymptote-faq-zh-cn",
	"asymptote-manual-zh-cn",
	"latex-tds",	// only source
	"biber",	// packaged separately
	"euro-ce",	// nonfree license
	"latexmk",	// packaged separately
        "uwmslide",	// artistic (non-free)
	"texdiff",	// artistic (non-free)
	NULL,
};
char *rem[] = {		/* any file beginning with this will be removed */
	"texmf-dist/doc/info/kpathsea.info",
	"texmf-dist/scripts/context/stubs/source",
	"readme-txt.dir",
	"tlpkg/installer",
	"install-tl",
	NULL,
};
char *fedora_license[] = {
#include "texlive-fedora-licenses.h"
	NULL, NULL
};
char *get_line() {
	if ( pos<size ) {
		off_t rpos;
		while ( pos<size && m[pos] < ' ' ) pos++;
		if ( pos == size ) return NULL;
		rpos = pos;
		while ( pos<size && m[pos] != '\n' ) pos++;
		if ( pos == size ) return NULL;
		m[pos] = 0;
		return &m[rpos];
	} else {
		return NULL;
	}
}
int get_token( char *s, match *m ) {
	int i, found = -1;
//	char *r;
	for ( i=0; m[i].token; i++ ) {
		if ( !strncmp(s, m[i].token, m[i].s?m[i].s:(m[i].s=strlen(m[i].token))) ) {
			if ( found == -1 ) {
				found = i;
			} else {
				if ( m[found].s < m[i].s ) found = i;
			}
		}
	}
	if ( found != -1 ) {
		return m[found].num;
	}
//	r = strchr(s,'\n');
//	*r = '\0';
//	fprintf(stderr,"No match: '%s'\nin '", s);
//	*r = '\n';
//	for ( i=0; m[i].token; i++ ) {
//		fprintf(stderr, "%s ", m[i].token);
//	}
//	fprintf(stderr, "'\nin package %s\n", pkg[p-1].name);
//	exit(1);
	return 0;
}
char *put_token( int t, match *m ) {
	for ( ;m->token; m++ ) {
		if ( m->num == t ) return m->token;
	}
	return NULL;
}
unsigned long hash(char *str) {
	unsigned long hash = 5381;
	int c;
	while ((c = *str++))
		hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
	return hash;
}
enum {FT_NONE, FT_DOC, FT_RUN, FT_SRC, FT_BIN};
void skipspace(char **sp) {
	char *s = *sp;
	while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++;
	while (*s == '%') {
		while ( *s != '\n' ) s++;
		while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++;
	}
	*sp = s;
}
void parse() {
	char *l;
	int filetype = FT_NONE;
	while ( (l=get_line()) ) {
		if ( !*l ) continue;
		if ( *l == ' ' ) {
			char pkgname[0x100];
			unsigned long pkghash;
			char *end = strchr(++l, ' ');
			if ( end ) {
				*end = '\0';
			}
			if ( pkg[p-1].reloc ) {
				char *rel = strstr(l, "RELOC");
				char *new_l = NULL;
				int ret;
				ret = asprintf(&new_l, "texmf-dist%s", rel+5);
				if (ret == -1) {
					fprintf(stderr, "asprintf failed?");
				}
				l = new_l;
			}
			if (!strncmp(l, "texmf-dist/doc/man/man", 22)) {  /* does package have any man pages? */
				pkg[p-1].has_man = 1;
				if ( l[strlen(l)-2] == '.' && l[strlen(l)-1] >= '0' && l[strlen(l)-1] <= '9' ) {
					pkg[p-1].runf = realloc(pkg[p-1].runf, (pkg[p-1].runfs+1)*sizeof(char *));
					pkg[p-1].runf[pkg[p-1].runfs] = l;
					pkg[p-1].runfs++;
					snprintf(pkgname, sizeof(pkgname), "%s", pkg[p-1].name);
					goto skip;
				}
				goto skip;
			}
			if (!strncmp(l, "texmf-dist/doc/info/", 20)) {  /* does package have any info pages? */
				pkg[p-1].has_info = 1;
				if ( !strncmp(&l[strlen(l)-5], ".info", 5) ) {
					pkg[p-1].runf = realloc(pkg[p-1].runf, (pkg[p-1].runfs+1)*sizeof(char *));
					pkg[p-1].runf[pkg[p-1].runfs] = l;
					pkg[p-1].runfs++;
					snprintf(pkgname, sizeof(pkgname), "%s", pkg[p-1].name);
					goto skip;
				}
				goto skip;
			}
			switch ( filetype ) {
				case FT_RUN:
#ifdef PACKAGE_DOCS
#ifdef MERGE_DOCS
				case FT_DOC:
#endif
#endif
					pkg[p-1].runf = realloc(pkg[p-1].runf, (pkg[p-1].runfs+1)*sizeof(char *));
					pkg[p-1].runf[pkg[p-1].runfs] = l;
					pkg[p-1].runfs++;
					snprintf(pkgname, sizeof(pkgname), "%s", pkg[p-1].name);
					break;
#ifdef PACKAGE_DOCS
#ifndef MERGE_DOCS
				case FT_DOC:
					pkg[p-1].docf = realloc(pkg[p-1].docf, (pkg[p-1].docfs+1)*sizeof(char *));
					pkg[p-1].docf[pkg[p-1].docfs] = l;
					pkg[p-1].docfs++;
					snprintf(pkgname, sizeof(pkgname), "%s-doc", pkg[p-1].name);
					break;
#endif
#else
				case FT_DOC:
					pkg[p-1].docf = realloc(pkg[p-1].docf, (pkg[p-1].docfs+1)*sizeof(char *));
					pkg[p-1].docf[pkg[p-1].docfs] = l;
					pkg[p-1].docfs++;
					snprintf(pkgname, sizeof(pkgname), "%s-doc", pkg[p-1].name);
					continue;
#endif
				case FT_SRC:
					pkg[p-1].srcf = realloc(pkg[p-1].srcf, (pkg[p-1].srcfs+1)*sizeof(char *));
					pkg[p-1].srcf[pkg[p-1].srcfs] = l;
					pkg[p-1].srcfs++;
					snprintf(pkgname, sizeof(pkgname), "%s-source", pkg[p-1].name);
#ifndef PACKAGE_SOURCE
					continue;
#endif
					break;
				case FT_BIN:
					pkg[p-1].binf = realloc(pkg[p-1].binf, (pkg[p-1].binfs+1)*sizeof(char *));
					pkg[p-1].binf[pkg[p-1].binfs] = l;
					pkg[p-1].binfs++;
					snprintf(pkgname, sizeof(pkgname), "%s", pkg[p-1].name);
					break;
				default:
					fprintf(stderr, "No filetype: %s\n", l);
					exit(1);
			}
skip:
			pkghash = hash(pkgname);
			end = strrchr(l, '/');
			if (!end) end = l;
			if ( end ) {
				int i;
				unsigned long h;
				char saved = *end;
				*end = '\0';
				h = hash(l);
				for ( i=0; i<dirs; i++ ) {
					if ( dir[i].dirhash == h && !strcmp(l, dir[i].dir) ) {
						int n;
						for ( n=0; n<dir[i].pkgs; n++ ) {
							if ( dir[i].pkghash[n] == pkghash && !strcmp(dir[i].pkg[n], pkgname) ) {
								goto exit;
							}
						}
						dir[i].pkg = realloc(dir[i].pkg, (dir[i].pkgs+1)*sizeof(char *));
						dir[i].pkghash = realloc(dir[i].pkghash, (dir[i].pkgs+1)*sizeof(unsigned long));
						dir[i].lic = realloc(dir[i].lic, (dir[i].pkgs+1)*sizeof(int));
						dir[i].pkg[dir[i].pkgs] = strdup(pkgname);
						dir[i].pkghash[dir[i].pkgs] = pkghash;
						dir[i].lic[dir[i].pkgs] = pkg[p-1].catalogue_license;
						dir[i].pkgs++;
						goto exit;
					}
				}
				dirs++;
				dir = realloc(dir, dirs*sizeof(dir_type));
				dir[dirs-1].dir = strdup(l);
				dir[dirs-1].dirhash = h;
				dir[dirs-1].pkgs = 1;
				dir[dirs-1].pkg = malloc(sizeof(char *));
				dir[dirs-1].pkghash = malloc(sizeof(unsigned long));
				dir[dirs-1].lic = malloc(sizeof(int));
				dir[dirs-1].pkg[0] = strdup(pkgname);
				dir[dirs-1].pkghash[0] = pkghash;
				dir[dirs-1].lic[0] = pkg[p-1].catalogue_license;
exit:
				*end = saved;
			}
			continue;
		}
next_name:
		if ( !strncmp(l,"name ", 5) ) {
			size_t sarch, sname;
			int i, blacklisted = 0;
			for (i=0; pkg_blacklist[i]; i++) {
				if ( !strncmp(l+5, pkg_blacklist[i], strlen(pkg_blacklist[i])) ) {
					blacklisted = 1;
					break;
				}
			}
			if (!blacklisted) {
				for (i=0; fedora_license[i]; i+=2) {
					if ( !strcmp(l+5, fedora_license[i]) && !fedora_license[i+1]) {
						blacklisted = 1;
						break;
					}
				}
			}
			if ( blacklisted ) {
				fprintf(stderr, "Blacklisted: %s\n", pkg_blacklist[i]);
				while ( (l=get_line()) ) {
					if ( !strncmp(l, "name ", 5) ) break;
				}
				if (!l) continue;
				goto next_name;
			}
			p++;
			pkg = realloc(pkg, p*sizeof(package));
			memset(&pkg[p-1], 0, sizeof(package));
			sarch = strlen(arch);
			sname = strlen(l+5);
			if ( sname > sarch && !strncmp(&(l+5)[sname-sarch], arch, sarch) ) {
				pkg[p-1].name = calloc(sname-sarch+5, 1);
				memcpy(pkg[p-1].name, l+5, sname-sarch);
				memcpy(&pkg[p-1].name[sname-sarch], "ARCH", 4);
			} else {
				pkg[p-1].name = l+5;
			}
			pkg[p-1].namehash = hash(pkg[p-1].name);
			filetype = FT_NONE;
			/* look for license first */
			{
				off_t opos = pos;
				while ( (l=get_line()) ) {
					m[pos] = '\n';
					if ( !strncmp(l, "name ", 5) ) break;
					if ( !strncmp(l,"catalogue-license ", 18) ) {
						pkg[p-1].catalogue_license = get_token(l+18, license);
						if ( pkg[p-1].catalogue_license & LIC_PROBLEMATIC ) printf("L: %s - %s\n", pkg[p-1].name, put_token(pkg[p-1].catalogue_license, spec_license));
						break;
					}
				}
				pos = opos;
			}
			continue;
		}
		if ( !strncmp(l,"category ", 9) ) {
			pkg[p-1].category = get_token(l+9, category);
			continue;
		}
		if ( !strncmp(l,"shortdesc ", 10) ) {
			size_t len;
			pkg[p-1].shortdesc = l+10;
			len = strlen(pkg[p-1].shortdesc);
			if ( pkg[p-1].shortdesc[len-1] == '.' ) pkg[p-1].shortdesc[len-1] = '\0';
			continue;
		}
		if ( !strncmp(l,"longdesc ", 9) ) {
			pkg[p-1].longdesc = realloc(pkg[p-1].longdesc, (pkg[p-1].longdesc_lines+1)*sizeof(char *));
			pkg[p-1].longdesc[pkg[p-1].longdesc_lines] = l+9;
			pkg[p-1].longdesc_lines++;
			continue;
		}
		if ( !strncmp(l,"docfiles ", 9) ) {
			filetype = FT_DOC;
			continue;
		}
		if ( !strncmp(l,"relocated 1", 11) ) {
			pkg[p-1].reloc = 1;
			continue;
		}
		if ( !strncmp(l,"runfiles ", 9) ) {
			filetype = FT_RUN;
			continue;
		}
		if ( !strncmp(l,"srcfiles ", 9) ) {
			filetype = FT_SRC;
			continue;
		}
		if ( !strncmp(l,"binfiles ", 9) ) {
			filetype = FT_BIN;
			continue;
		}
		if ( !strncmp(l,"depend ", 7) ) {
			pkg[p-1].dep = realloc(pkg[p-1].dep, (pkg[p-1].reqs+1)*sizeof(char *));
			pkg[p-1].req = realloc(pkg[p-1].req, (pkg[p-1].reqs+1)*sizeof(package *));
			pkg[p-1].dep[pkg[p-1].reqs] = l+7;
			pkg[p-1].req[pkg[p-1].reqs] = NULL;
			pkg[p-1].reqs++;
			continue;
		}
		if ( !strncmp(l,"execute ", 8) ) {
			pkg[p-1].exe = realloc(pkg[p-1].exe, (pkg[p-1].exes+1)*sizeof(char *));
			pkg[p-1].exe[pkg[p-1].exes] = l+8;
			pkg[p-1].exes++;
			continue;
		}
		if ( !strncmp(l,"catalogue-ctan ", 15) ) {
			pkg[p-1].catalogue_ctan = l+15;
			continue;
		}
		if ( !strncmp(l,"catalogue-license ", 18) ) {
			pkg[p-1].catalogue_license = get_token(l+18, license);
			{
				int n;
				for (n=0; fedora_license[n]; n+=2) {
					if (!strcmp(fedora_license[n], pkg[p-1].name)) {
						pkg[p-1].fedora_license = fedora_license[n+1];
						break;
					}
				}
			}
			continue;
		}
		if ( !strncmp(l,"catalogue-date ", 15) ) {
			pkg[p-1].catalogue_date = l+15;
			continue;
		}
		if ( !strncmp(l,"catalogue-version ", 18) ) {
			pkg[p-1].catalogue_version = l+18;
			/* substitute unallowed '/', '-', ' ', '~' characters with '_' */
			{
				char *v;
				for ( v=pkg[p-1].catalogue_version; *v; v++ ) {
					if ( *v == '/' || *v == '-' || *v == ' ' || *v == '~' || *v == ',' || *v == '(' || *v == ')') *v = '_';
				}
			}
			continue;
		}
		if ( !strncmp(l,"revision ", 9) ) {
			pkg[p-1].revision = l+9;
			continue;
		}
		if ( !strncmp(l,"containersize ", 14) ||
		     !strncmp(l,"containermd5 ", 13) ||
		     !strncmp(l,"doccontainersize ", 17) ||
		     !strncmp(l,"doccontainermd5 ", 16) ||
		     !strncmp(l,"srccontainersize ", 17) ||
		     !strncmp(l,"srccontainermd5 ", 16) ||
		     !strncmp(l,"catalogue ", 10) ||
                     !strncmp(l,"postaction ", 11)
		) {
			continue;
		}
		fprintf(stderr, "unknown token: '%s'\n", l);
	}
}
package **inst;
int installed, srcno=100, mainsrcno = 7000, mainpkg;
FILE *fpack, *ffile, *funpack, *fsrc, *fremove, *ffont;
char *cnf_files[] = {
	"texmf-dist/web2c/fmtutil.cnf",
	"texmf-dist/web2c/updmap.cfg",
	"texmf-dist/web2c/texmf.cnf",
	"texmf-dist/web2c/context.cnf",
	"texmf-dist/web2c/mktex.cnf",
	"texmf-dist/dvips/config/config.ps",		/* rhbz#441171 */
	"texmf-dist/tex/generic/config/language.dat",	/* rhbz#929367 */
	NULL,
};
int main_written;
void append_filelist( char *pkg, char *pkgsuf, int files, char **filelist, char *pkglicense ) {
	char pkgname[0x100];
	unsigned long pkghash;
	int x, y, n, bin = 0;
	char *binpos;
	strncpy(pkgname, pkg, sizeof(pkgname));
	if ( pkgsuf && *pkgsuf ) {
		strcat(pkgname, "-");
		strcat(pkgname, pkgsuf);
	}
	pkghash = hash(pkgname);
	if ( (binpos=strstr(pkgname, ".ARCH")) ) {
		bin = 1;
		*binpos = '\0';
		strcat(binpos, "-bin");
	}
	if ( pkglicense && get_token(pkglicense, license) && !(get_token(pkglicense, license)&LIC_PROBLEMATIC) ) {
			fprintf(ffile, "%%files %s\n%%defattr(-,root,root)\n%%doc %s.txt\n", mainpkg?(!main_written?"":pkgsuf):pkgname, pkglicense);
	} else {
		fprintf(ffile, "%%files %s\n%%defattr(-,root,root)\n", mainpkg?(!main_written?"":pkgsuf):pkgname);
	}
	if ( bin ) {
		*binpos = '\0';
		strcat(binpos, ".ARCH");
	}
	for (y=0; y<dirs; y++) {
		for (x=0; x<dir[y].pkgs; x++) {
			if ( dir[y].pkghash[x] == pkghash && !strcmp(dir[y].pkg[x], pkgname) ) {
				size_t bin_index = 0;
				if ( bin ) bin_index = 5+strlen(arch);
				if ( dir[y].pkgs == 1 ) {
					if ( !bin ) {
#ifdef SHORTEN_FILELISTS
						int found = 0;
#endif
						for (n=0; n<dirs; n++) {
							if ( y==n ) continue;
							if ( !strncmp(dir[n].dir, dir[y].dir, strlen(dir[y].dir)) ) {
#ifdef SHORTEN_FILELISTS
								found = 1;
#endif
								break;
							}
						}
#ifdef SHORTEN_FILELISTS
						if ( !found ) {
							fprintf(ffile, "%%{_texdir}/%s/*\n", dir[y].dir);
							for (n=0; n<files; n++) {			/* stupid styles contain files like ".tex" which are not caught via "*" */
								char *name = strrchr(filelist[n], '/');
								if (name && name[1] == '.') {
									fprintf(ffile, "%%{_texdir}/%s\n", filelist[n]);
								}
							}
							continue;
						}
#endif
					}
				}
				for (n=0; n<files; n++) {
					char *end = strrchr(filelist[n], '/');
					if (!end) end = filelist[n];
					if (end) {
						char saved = *end;
						*end = '\0';
						if ( !strcmp(dir[y].dir, filelist[n]) ) {
							int i;
							*end = saved;
							if ( strstr(&filelist[n][bin_index], arch) ) continue; /* fool texlive.infra - don't install lzma/xz */
							if (strstr(&filelist[n][bin_index], "win32") || strstr(&filelist[n][bin_index], "mswin") ||
							    strstr(&filelist[n][bin_index], "Win32") || strstr(&filelist[n][bin_index], "tlmgr") ||
							    !strncmp(&filelist[n][bin_index], "texmf-dist/source/", 18) ||
							    strstr(&filelist[n][bin_index], ".swf")) {
								fprintf(fremove, "rm -f %%{buildroot}/%s/%s\n", bin?"%{_bindir}":"%{_texdir}", &filelist[n][bin_index]);
								printf("*** %s\n", &filelist[n][bin_index]);
								goto next;
							}
							for (i=0; rem[i]; i++) {
								if (!strncmp(&filelist[n][bin_index], rem[i], strlen(rem[i]))) {
									fprintf(fremove, "rm -f %%{buildroot}/%s/%s\n", bin?"%{_bindir}":"%{_texdir}", &filelist[n][bin_index]);
									printf("*** %s\n", &filelist[n][bin_index]);
									goto next;
								}
							}
							if (!strncmp(&filelist[n][bin_index], "texmf-dist/doc/man/man", 22)) {  /* relocate man pages to correct paths */
								size_t sz = strlen(&filelist[n][bin_index]);
								char *man = &filelist[n][bin_index];
								if (man[sz-1] >= '0' && man[sz-1] <= '9') {
									fprintf(ffile, "%%{_mandir}/%s*\n", &filelist[n][bin_index+19]);
								}
								goto next;
							}
							if (!strncmp(&filelist[n][bin_index], "texmf-dist/doc/info", 19)) {  /* relocate path for info files, ignore all other files such as 'dir' */
								if (!strncmp(&filelist[n][strlen(filelist[n])-5], ".info", 5)) {
									fprintf(ffile, "%%{_infodir}/%s*\n", &filelist[n][bin_index+20]);
								}
								goto next;
							}
							if (!strcmp(&filelist[n][bin_index], "texmf-dist/web2c/updmap.cfg")) {
								fprintf(fremove, "\n# disable all Maps/MixedMaps we add them by scriptlets\n");
								fprintf(fremove, "sed -i '/^M/d' %%{buildroot}%%{_texdir}/texmf-dist/web2c/updmap.cfg\n");
							} else
							if (!strcmp(&filelist[n][bin_index], "texmf-dist/web2c/fmtutil.cnf")) {
								fprintf(fremove, "\n# disable all formats\n");
								fprintf(fremove, "sed -i '/^[a-z].*$/s/^/\\#\\!\\ /' %%{buildroot}%%{_texdir}/texmf-dist/web2c/fmtutil.cnf\n");
							} else
							if (!strcmp(&filelist[n][bin_index], "texmf-dist/tex/generic/config/language.us")) {
								fprintf(fremove, "\n# disable all hyphenations\n");
								fprintf(fremove, "cp -f %%{buildroot}%%{_texdir}/texmf-dist/tex/generic/config/language.us %%{buildroot}%%{_texdir}/texmf-dist/tex/generic/config/language.dat\n");
							} else
							if (!strcmp(&filelist[n][bin_index], "texmf-dist/tex/generic/config/language.us.def")) {
								fprintf(fremove, "\n# disable all hyphenations\n");
								fprintf(fremove, "cp -f %%{buildroot}%%{_texdir}/texmf-dist/tex/generic/config/language.us.def %%{buildroot}%%{_texdir}/texmf-dist/tex/generic/config/language.def\n");
							}
							{			/* add %config(noreplace) for config files */
								int i;
								for ( i=0; cnf_files[i]; i++ ) {
									if ( !strcmp(&filelist[n][bin_index], cnf_files[i]) ) {
										fprintf(ffile, "%%config(noreplace) ");
										break;
									}
								}
							}
							fprintf(ffile, "%s/%s\n", bin?"%{_bindir}":"%{_texdir}", &filelist[n][bin_index]);
						}
next:
						*end = saved;
					}
				}
			}
		}
	}
	fprintf(ffile, "\n");
}
#if 0
static void provide_file(package *p, char *suf) {
	int n;
	for (n=0; n<p->runfs; n++) {
		if ( !strncmp(&p->runf[n][strlen(p->runf[n])-strlen(suf)], suf, strlen(suf)) ) {
			fprintf(fpack, "Provides: tex(%s) = %%{tl_version}\n", strrchr(p->runf[n], '/')+1);
		   }
	}
}
static void fill_provide_file(package *p, char *suf) {
	int n;
	for (n=0; n<p->runfs; n++) {
		if ( !strncmp(&p->runf[n][strlen(p->runf[n])-strlen(suf)], suf, strlen(suf)) ) {
			fprintf(fpack, "Provides: tex(%s) = %%{tl_version}\n", strrchr(p->runf[n], '/')+1);
		   }
	}
}
#endif
static void fill_file_reqprov() {
	int i, j, n, k;
	char ss[0x100];
	char *se;
	char *sufs[] = { ".tfm", ".ttf", ".ttc", ".pfa", ".pfb", ".pcf",
			 ".otf", ".tex", ".cnf", ".cfg", ".def", ".dat",
			 ".ldf", ".fd", ".enc", ".map", ".vf", ".vpl",
			 ".clo", ".bug", ".bg2", ".cbx", ".bbx", ".cls",
			 ".sty", NULL };
	for (i=0; i<p; i++) {
		for (n=0; n<pkg[i].runfs; n++) {
			for (k=0; sufs[k]; k++) {
				if (!strncmp(&pkg[i].runf[n][strlen(pkg[i].runf[n])-strlen(sufs[k])], sufs[k], strlen(sufs[k]))) {
					pkg[i].file_prov = realloc(pkg[i].file_prov, (pkg[i].file_provs+1)*sizeof(char *));
					pkg[i].file_prov[pkg[i].file_provs] = strdup(strrchr(pkg[i].runf[n], '/')+1);
					pkg[i].file_provs++;
				}
			}
			if ( !strncmp(&pkg[i].runf[n][strlen(pkg[i].runf[n])-4], ".sty", 4) ||
			     !strncmp(&pkg[i].runf[n][strlen(pkg[i].runf[n])-4], ".cls", 4) ||
			     !strncmp(&pkg[i].runf[n][strlen(pkg[i].runf[n])-4], ".ldf", 4) ||
			     !strncmp(&pkg[i].runf[n][strlen(pkg[i].runf[n])-4], ".bbx", 4) ||
			     !strncmp(&pkg[i].runf[n][strlen(pkg[i].runf[n])-4], ".cbx", 4) ||
			     !strncmp(&pkg[i].runf[n][strlen(pkg[i].runf[n])-4], ".bug", 4) ||
			     !strncmp(&pkg[i].runf[n][strlen(pkg[i].runf[n])-4], ".bg2", 4) ||
			     !strncmp(&pkg[i].runf[n][strlen(pkg[i].runf[n])-4], ".clo", 4)
			   ) {
				char fl[0x100] = "texlive.expanded/";
				FILE *f;
				char *m, *s;
				off_t size;
				strcat(fl, pkg[i].runf[n]);
				if ( !(f=fopen(fl,"rt")) ) {
					printf("file missing: %s\n", pkg[i].runf[n]);
					exit(1);
				}
				fseek(f, 0, SEEK_END);
				size = ftell(f);
				fseek(f, 0, SEEK_SET);
				m = malloc(size+1);
				fread(m, size, 1, f);
				fclose(f);
				m[size] = '\0';
				if ( !strncmp(&pkg[i].runf[n][strlen(pkg[i].runf[n])-4], ".bbx", 4) ) {
					for ( s=m; (s=strstr(s,"\\RequireBibliographyStyle{")); ) {
						s += 26;
						se = strchr(s, '}');
						*se = '\0';
						strcpy(ss, s);
						strcat(ss, ".bbx");
						for (k=0; k<pkg[i].file_reqs; k++) {
							if (!strcmp(pkg[i].file_req[k], ss)) goto next_bbx;
						}
						pkg[i].file_req = realloc(pkg[i].file_req, (pkg[i].file_reqs+1)*sizeof(char *));
						pkg[i].file_req[pkg[i].file_reqs] = strdup(ss);
						pkg[i].file_reqs++;
next_bbx:
						*se = '}';
					}
					goto skip;
				}
				if ( !strncmp(&pkg[i].runf[n][strlen(pkg[i].runf[n])-4], ".cbx", 4) ) {
					for ( s=m; (s=strstr(s,"\\RequireCitationStyle{")); ) {
						s += 22;
						se = strchr(s, '}');
						*se = '\0';
						strcpy(ss, s);
						strcat(ss, ".cbx");
						for (k=0; k<pkg[i].file_reqs; k++) {
							if (!strcmp(pkg[i].file_req[k], ss)) goto next_cbx;
						}
						pkg[i].file_req = realloc(pkg[i].file_req, (pkg[i].file_reqs+1)*sizeof(char *));
						pkg[i].file_req[pkg[i].file_reqs] = strdup(ss);
						pkg[i].file_reqs++;
next_cbx:
						*se = '}';
					}
					goto skip;
				}
				for ( s=strstr(m, "\\ProvidesPackage"); s; s=strstr(s, "\\ProvidesPackage") ) {
					char *os = s+16;
					char dep[0x100], *d;
					dep[0] = '\0';
					for (; s>=m; s--) {
						if (*s == '\n') break;
					}
					while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++;
					if ( *s == '%' ) goto nextprov;
					s = os;
					skipspace(&s);
					if ( *s == '[' ) {
						s++;
						while (*s != ']') if (*s == '%') skipspace(&s); else s++;
						s++;
						skipspace(&s);
					}
					if ( *s != '{' ) goto nextprov;
					s++;
					for ( d=dep, os=s; ; s++ ) {
						if ( *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r' ) continue;
						if ( (*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || (*s >= '0' && *s <= '9') || *s == '-' ) {
							*d = *s;
							d++;
							continue;
						}
						if ( *s == '%') {
							skipspace(&s);
							s--;
							continue;
						}
						if ( *s == ',' || *s == '}' ) {
							*d = '\0';
							strcpy(ss, dep);
							strcat(ss, ".sty");
							for (k=0; k<pkg[i].file_provs; k++) {
								if (!strcmp(ss, pkg[i].file_prov[k])) goto nextprov;
							}
							if ( *dep ) {
								pkg[i].file_prov = realloc(pkg[i].file_prov, (pkg[i].file_provs+1)*sizeof(char *));
								pkg[i].file_prov[pkg[i].file_provs] = strdup(ss);
								pkg[i].file_provs++;
							}
							if ( *s == '}' ) break;
							d = dep;
							continue;
						}
						goto nextprov;
					}
nextprov:
					s = os;
				}
				for ( s=strstr(m, "\\RequirePackage"); s; s=strstr(s, "\\RequirePackage") ) {
					char *os = s+15;
					char dep[0x100], *d;
					for (; s>=m; s--) {
						if (*s == '\n') break;
					}
					while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++;
					if ( *s == '%' ) goto nextreq;
					s = os;
					if (!strncmp(s, "WithOptions", 11)) s+=11;
					skipspace(&s);
					if ( *s == '[' ) {
						s++;
						while (*s != ']') if (*s == '%') skipspace(&s); else s++;
						s++;
						skipspace(&s);
					}
					if ( *s != '{' ) goto nextreq;
					s++;
					for ( d=dep, os=s; ; s++ ) {
					if ( *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r' ) continue;
						if ( (*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || (*s >= '0' && *s <= '9') || *s == '-' ) {
							*d = *s;
							d++;
							continue;
						}
						if ( *s == '%') {
							skipspace(&s);
							s--;
							continue;
						}
						if ( *s == ',' || *s == '}' ) {
							*d = '\0';
							strcpy(ss, dep);
							strcat(ss, ".sty");
							for (k=0; k<pkg[i].file_reqs; k++) {
								if (!strcmp(ss, pkg[i].file_req[k])) goto nextreq;
							}
							for (k=0; k<pkg[i].file_provs; k++) {
								if (!strcmp(ss, pkg[i].file_prov[k])) goto nextreq;
							}
							if ( *dep ) {
								pkg[i].file_req = realloc(pkg[i].file_req, (pkg[i].file_reqs+1)*sizeof(char *));
								pkg[i].file_req[pkg[i].file_reqs] = strdup(ss);
								pkg[i].file_reqs++;
							}
							if ( *s == '}' ) break;
							d = dep;
							continue;
						}
						goto nextreq;
					}
nextreq:
					s = os;
				}
				for ( s=strstr(m, "\\input"); s; s=strstr(s, "\\input") ) {
					char *os = s+6;
					char dep[0x100], *d;
					int has_space = 0;
					for (s--; s>=m; s--) {
						if (*s == '\n') break;
						if (*s != ' ' || *s != '\t') goto nextinput;
					}
					s++;
					while (*s == ' ' || *s == '\t') s++;
					if ( *s == '%' ) goto nextinput;
					s = os;
					if (*s == ' ' || *s == '\t') {
						has_space = 1;
						while (*s == ' ' || *s == '\t') s++;
					}
					if (*s == '{') {
						has_space = 1;
						s++;
						while (*s == ' ' || *s == '\t') s++;
					}
					if ( !has_space ) goto nextinput;
					for (d=dep; (*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || (*s >= '0' && *s <= '9') || *s == '-' || *s == '.'; s++) {
						*d = *s;
						d++;
					}
					if ( d == dep ) goto nextinput;
					while (*s == ' ' || *s == '\t') s++;
					if ( *s == '}' || *s == '%' || *s == '\n' || *s == '\r') {
						int x;
						size_t sz;
						*d = '\0';
						if (!strchr(dep, '.')) strcat(dep, ".tex");
						sz = strlen(dep);
						for ( x=0; x<pkg[i].runfs; x++ ) {
							if ( !strcmp(&pkg[i].runf[x][strlen(pkg[i].runf[x])-sz], dep) && pkg[i].runf[x][strlen(pkg[i].runf[x])-sz-1] == '/' ) {
								goto nextinput;
							}
						}
						pkg[i].file_req = realloc(pkg[i].file_req, (pkg[i].file_reqs+1)*sizeof(char *));
						pkg[i].file_req[pkg[i].file_reqs] = strdup(dep);
						pkg[i].file_reqs++;
					}
nextinput:
					s = os;
				}
skip:
				free(m);
			}
		}
		/* Do not require self-provided files */
		for (k=0; k<pkg[i].file_reqs; k++) {
			for (n=0; n<pkg[i].file_provs; n++) {
				if (!strcmp(pkg[i].file_prov[n], pkg[i].file_req[k])) {
					memmove(&pkg[i].file_req[k], &pkg[i].file_req[k+1], (pkg[i].file_reqs-k-1)*sizeof(char*));
					pkg[i].file_reqs--;
					break;
				}
			}
		}
	}
	for (i=0; i<p; i++) {
		for (n=0; n<pkg[i].file_reqs; n++) {
			int found = 0;
			for (k=0; k<p; k++) {
				for (j=0; j<pkg[k].file_provs; j++) {
					if ( !strcmp(pkg[k].file_prov[j], pkg[i].file_req[n]) ) {
						found = 1;
						break;
					}
				}
				if (found) break;
			}
			if (!found) {
				fprintf(stderr, "Nothing provides: %s required by %s\n", pkg[i].file_req[n], pkg[i].name);
				memmove(&pkg[i].file_req[n], &pkg[i].file_req[n+1], (pkg[i].file_reqs-n-1)*sizeof(char*));
				pkg[i].file_reqs--;
				n--;
			}
		}
	}
}
static char *print_noarch_version( package *p ) {
	static char noarchver[0x100];
	if ( p->catalogue_version ) {
		snprintf(noarchver, sizeof(noarchver), "svn%s.%s", p->revision, p->catalogue_version );
	} else {
		snprintf(noarchver, sizeof(noarchver), "svn%s.0", p->revision);
	}
	return noarchver;
}
static char *skipspaces( char *s ) {
	while ( isblank(*s) ) s++;
	return s;
}
int level;
void solve(char *name) {
	unsigned long h;
	int i, found = 0, doc_expanded = 0;
#ifdef SRPMS
	FILE *ofpack = NULL, *offile = NULL, *ofunpack = NULL, *ofsrc = NULL, *ofremove = NULL, *offont = NULL;
#endif
	h = hash(name);
	if ( !fpack ) {
		fpack = fopen("_packages.spec", "wt");
	}
	if ( !ffile ) {
		ffile = fopen("_files.spec", "wt");
	}
	if ( !funpack ) {
		funpack = fopen("_unpack.spec", "wt");
	}
	if ( !fsrc ) {
		fsrc = fopen("_sources.spec", "wt");
	}
	if ( !fremove ) {
		fremove = fopen("_remove.spec", "wt");
	}
	if ( !ffont ) {
		ffont = fopen("_font.spec", "wt");
	}
	for (i=0; i<installed; i++) {
		if ( inst[i]->namehash == h && !strcmp(inst[i]->name, name) ) {
			return;
		}
	}
	for (i=0; i<level; i++) printf("\t");
	printf("%s\n", name);
	for (i=0; i<p; i++) {
		if ( pkg[i].namehash == h && !strcmp(pkg[i].name, name)) {
			int n, has_noarch_pkg = 0;
			if ( pkg[i].catalogue_license & LIC_NOTALLOWED ) {
				printf("Bad license: %s\n", pkg[i].name);
				continue;
			}
			if ( pkg[i].srcfs && !(pkg[i].runfs || pkg[i].docfs || pkg[i].exes || pkg[i].reqs) ) {
				printf("onlysrc: %s\n", name);
				continue;
			}
			level++;
			inst = realloc(inst, (installed+1)*sizeof(package*));
			inst[installed++] = &pkg[i];
			if ( pkg[i].exes ) {
				for (n=0; n<pkg[i].exes; n++) {
					int m;
					for (m=0; m<level; m++) printf("\t");
					printf("> %s\n", pkg[i].exe[n]);
				}
			}
			if ( pkg[i].binfs ) {
				char s[0x100], *pp;
				unsigned long hh;
				strcpy(s, name);
				pp = strstr(s, ".ARCH");
				*pp = 0;
				hh = hash(s);
				for (n=0; n<p; n++) {
					if ( pkg[n].namehash == hh && !strcmp(pkg[n].name, s)) {
						has_noarch_pkg = pkg[n].main_pkg_written;
						break;
					}
				}
				if ( has_noarch_pkg && pkg[n].catalogue_license & LIC_NOTALLOWED ) {
					printf("Bad license: %s\n", pkg[n].name);
					continue;
				}
				fprintf(fsrc, "Source%04d: "CTAN_URL"%s.%s.tar."UNPACK"\n", mainsrcno, s, arch);
				fprintf(funpack, UNPACK" -dc %%{SOURCE%d} | tar x -C %%{buildroot}\n", mainsrcno);
				mainsrcno++;
			}
			/* is it collection or scheme? then don't create a separate package for it and put it to main one */
			if ( !strncmp(name, "collection-", 11) || !strncmp(name, "scheme-", 7) ) {
				pkg[i].any_pkg_written = 1;
				fprintf(funpack, UNPACK" -dc %%{SOURCE%d} | tar x -C %%{buildroot}%%{_texdir}%s\n", mainsrcno, pkg[i].reloc?"/texmf-dist":"");
				fprintf(fpack, "%%package %s\n", name);
				if ( pkg[i].shortdesc ) {
					fprintf(fpack, "Summary: %s\n", pkg[i].shortdesc);
				} else {
					fprintf(fpack, "Summary: %s package\n", name);
				}
				fprintf(fpack, "Version: %s\n", print_noarch_version(&pkg[i]));
				fprintf(fpack, "Release: %%{tl_release}\n");
				fprintf(fpack, "BuildArch: noarch\n");
				fprintf(fsrc, "Source%04d: "CTAN_URL"%s.tar."UNPACK"\n", mainsrcno++, name);
				fprintf(fpack, "Requires: texlive-base\n");
				for (n=0; n<pkg[i].reqs; n++) {
					if ( pkg[i].req[n] ) {
						if ( pkg[i].req[n]->catalogue_license & LIC_NOTALLOWED ) {
							continue;
						}
						if ( pkg[i].req[n]->reqs || pkg[i].req[n]->runfs || pkg[i].req[n]->exes ) {
							if (strncmp(pkg[i].dep[n], "collection-", 11)) {
								fprintf(fpack, "Requires: tex-%s\n", pkg[i].dep[n]);
							} else {
								fprintf(fpack, "Requires: texlive-%s\n", pkg[i].dep[n]);
							}
							continue;
						}
#ifdef PACKAGE_DOCS
						if ( pkg[i].req[n]->docfs ) {
							fprintf(fpack, "Requires: texlive-%s-doc\n", pkg[i].dep[n]);
							continue;
						}
#endif
#ifdef PACKAGE_SOURCE
						if ( pkg[i].req[n]->srcfs ) {
							fprintf(fpack, "Requires: texlive-%s-source\n", pkg[i].dep[n]);
							continue;
						}
#endif
						if ( pkg[i].req[n]->binfs ) {
							size_t spost = strlen(pkg[i].dep[n])-5;
							if (strcmp(&pkg[i].dep[n][spost], ".ARCH")) {
								printf("Doesn't have .ARCH suffix!\n");
								exit(1);
							}
							pkg[i].dep[n][spost] = '\0';
							fprintf(fpack, "Requires: texlive-%s-bin\n", pkg[i].dep[n]);
							pkg[i].dep[n][spost] = '.';
							continue;
						}
					}
				}
				/* write virtual provides */
				if ( !strncmp(name, "collection-", 11) ) {
					if (!strcmp(name+11, "latexrecommended")) {
						fprintf(fpack, "Provides: tex(latex) = %%{tl_version}, texlive-latex = %%{tl_version}\n");
						fprintf(fpack, "Requires: texlive-collection-fontsrecommended\n");
					} else if (!strcmp(name+11, "latex")) {
						fprintf(fpack, "Provides: tex(latex-base) = %%{tl_version}\n");
					} else if (!strcmp(name+11, "basic")) {
						fprintf(fpack, "Provides: tex(tex) = %%{tl_version}, tex = %%{tl_version}\n");
						fprintf(fpack, "Requires: dvipdfmx, xdvik\n");
					} else if (!strcmp(name+11, "langcjk")) {
						fprintf(fpack, "Provides: tex(japanese) = %%{tl_version}\n");
						fprintf(fpack, "Provides: tex(east-asian) = %%{tl_version}\n");
						fprintf(fpack, "Obsoletes: texlive-east-asian < %%{tl_version}\n");
						fprintf(fpack, "Obsoletes: texlive-texmf-east-asian < %%{tl_version}\n");
					} else if (!strcmp(name+11, "documentation-base")) {
						fprintf(fpack, "Provides: texlive-texmf-doc = %%{tl_version}\n");
						fprintf(fpack, "Obsoletes: texlive-texmf-doc < %%{tl_version}\n");
					} else if (!strcmp(name+11, "fontsrecommended")) {
						fprintf(fpack, "Provides: tetex-fonts = 3.1-99\n");
						fprintf(fpack, "Obsoletes: tetex-fonts < 3.1-99\n");
						fprintf(fpack, "Provides: texlive-texmf-fonts = %%{tl_version}\n");
						fprintf(fpack, "Obsoletes: texlive-texmf-fonts < %%{tl_version}\n");
					} else if (!strcmp(name+11, "binextra")) {
						fprintf(fpack, "Obsoletes: texlive-utils < %%{tl_version}\n");
						fprintf(fpack, "Requires: dvipng\n");
					} else if (!strcmp(name+11, "xetex")) {
						fprintf(fpack, "Provides: tex(xetex) = %%{tl_version}\n");
						fprintf(fpack, "Obsoletes: texlive-texmf-xetex < %%{tl_version}\n");
					} else if (!strcmp(name+11, "fontutils")) {
						fprintf(fpack, "Requires: t1utils, psutils, lcdf-typetools\n");
					}
				}
				if ( !strcmp(name, "scheme-tetex") ) {
					fprintf(fpack, "Provides: tetex = 3.1-99\n");
					fprintf(fpack, "Obsoletes: tetex < 3.1-99\n");
					fprintf(fpack, "Obsoletes: texlive-dviutils < %%{tl_version}\n");
				}
				if ( !strcmp(name, "scheme-context") ) {
					fprintf(fpack, "Provides: tex(context) = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: texlive-texmf-context < %%{tl_version}\n");
				}
				if ( !strcmp(name, "ps2pk") ) {
					fprintf(fpack, "Provides: texlive-ps2pkm = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: texlive-ps2pkm < %%{tl_version}\n");
				}
				if ( !strcmp(name, "ps2pk-bin") ) {
					fprintf(fpack, "Provides: texlive-ps2pkm-bin%%{_isa} = %%{tl_version}\n");
					fprintf(fpack, "Provides: texlive-ps2pkm-bin = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: texlive-ps2pkm-bin < %%{tl_version}\n");
				}
				/* description */
				fprintf(fpack, "\n%%description %s\n", name);
				for (n=0; n<pkg[i].longdesc_lines; n++) {
					fprintf(fpack, "%s\n", pkg[i].longdesc[n]);
				}
				if ( !pkg[i].longdesc_lines ) fprintf(fpack, "%s package\n", name);
				if ( pkg[i].catalogue_date ) fprintf(fpack, "\ndate: %s\n", pkg[i].catalogue_date);
				fprintf(fpack, "\n");
				fprintf(ffile, "%%files %s\n%%defattr(-,root,root)\n\n", name);
				goto slv;
			}
#ifdef SRPMS
			if ( !pkg[i].binfs ) {
				char path[0x100];
				char p[0x100];
				ofpack = fpack;
				offile = ffile;
				ofunpack = funpack;
				ofsrc = fsrc;
				ofremove = fremove;
				offont = ffont;
				snprintf(path, sizeof(path), "specs/tex-%s", name);
				mkdir(path, 0775);
				snprintf(p, sizeof(p), "%s/_packages.spec", path);
				fpack = fopen(p, "wt");
				snprintf(p, sizeof(p), "%s/_files.spec", path);
				ffile = fopen(p, "wt");
				snprintf(p, sizeof(p), "%s/_unpack.spec", path);
				funpack = fopen(p, "wt");
				snprintf(p, sizeof(p), "%s/_sources.spec", path);
				fsrc = fopen(p, "wt");
				snprintf(p, sizeof(p), "%s/_remove.spec", path);
				fremove = fopen(p, "wt");
				snprintf(p, sizeof(p), "%s/_font.spec", path);
				ffont = fopen(p, "wt");
				snprintf(p, sizeof(p), "%s/_main.spec", path);
				symlink("../../_main_subpackage.spec", p);
				srcno = 0;
			}
			if ( pkg[i].catalogue_license ) fprintf(funpack, "ln -s %%{_texdir}/licenses/%s.txt %s.txt\n", put_token(pkg[i].catalogue_license, license), put_token(pkg[i].catalogue_license, license));
#endif
			/* write main packages */
			if ( pkg[i].runfs || pkg[i].reqs || pkg[i].exes ) {
				pkg[i].main_pkg_written = pkg[i].any_pkg_written = 1;
				fprintf(funpack, UNPACK" -dc %%{SOURCE%d} | tar x -C %%{buildroot}%%{_texdir}%s\n", srcno, pkg[i].reloc?"/texmf-dist":"");
#ifndef SRPMS
				fprintf(fpack, "%%package %s\n", name);
				fprintf(fpack, "Provides: tex-%s = %%{tl_version}\n", name);
#else
				fprintf(fpack, "Name: tex-%s\n", name);
				fprintf(fpack, "Obsoletes: texlive-%s texlive-%s-doc texlive-%s-fedora-fonts\n", name, name, name);
#endif
				fprintf(fpack, "License: %s\n", pkg[i].fedora_license?pkg[i].fedora_license:(put_token(pkg[i].catalogue_license, spec_license)?put_token(pkg[i].catalogue_license, spec_license):"LPPL"));
				if ( pkg[i].shortdesc ) {
					fprintf(fpack, "Summary: %s\n", pkg[i].shortdesc);
				} else {
					fprintf(fpack, "Summary: %s package\n", name);
				}
				fprintf(fpack, "Version: %s\n", print_noarch_version(&pkg[i]));
				fprintf(fpack, "Release: %%{tl_noarch_release}\n");
				fprintf(fpack, "BuildArch: noarch\n");
				if (!strcmp(name,"pdfcrop")) {
					fprintf(fpack, "AutoReqProv: No\n");
				}
				fprintf(fsrc, "Source%04d: "CTAN_URL"%s.tar."UNPACK"\n", srcno++, name);
				if ( pkg[i].has_man || pkg[i].has_info ) {
					char nm[0x100];
					FILE *f;
					snprintf(nm, sizeof(nm), "texlive/archive/%s.doc.tar."UNPACK, name);
					f = fopen(nm, "rb");
					if ( f ) {
						fprintf(funpack, UNPACK" -dc %%{SOURCE%d} | tar x -C %%{buildroot}%%{_texdir}%s\n", srcno, pkg[i].reloc?"/texmf-dist":"");
						fprintf(fsrc, "Source%04d: "CTAN_URL"%s.doc.tar."UNPACK"\n", srcno++, name);
						doc_expanded = 1;
						fclose(f);
					}
				}
				if ( strncmp(name, "kpathsea", 8) ) {
					fprintf(fpack, "Requires: texlive-base\n");
				} else {
					fprintf(fpack, "Provides: kpathsea = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: kpathsea < %%{tl_version}\n");
					fprintf(funpack, "\n# add reference to support old texmf tree\n"
					"sed -i 's|TEXMFLOCAL = $SELFAUTOPARENT/../texmf-local|TEXMFLOCAL = $SELFAUTOPARENT/../texmf|g' %%{buildroot}%%{_texdir}/texmf-dist/web2c/texmf.cnf\n\n");
				}
				if ( !strncmp(name, "asana-math", 10) ) {
					fprintf(fpack, "Provides: texlive-Asana-Math = %%{tl_version}.1\n");
					fprintf(fpack, "Obsoletes: texlive-Asana-Math < %%{tl_version}.1\n");
					fprintf(fpack, "Obsoletes: texlive-Asana-Math-fedora-fonts < %%{tl_version}.1\n");
				}
				if ( !strncmp(name, "lineara", 10) ) {
					fprintf(fpack, "Provides: texlive-linearA = %%{tl_version}.1\n");
					fprintf(fpack, "Obsoletes: texlive-linearA < %%{tl_version}.1\n");
					fprintf(fpack, "Obsoletes: texlive-linearA-fedora-fonts < %%{tl_version}.1\n");
				}
				if ( !strncmp(name, "minted", 6) ) {
					fprintf(fpack, "Requires: python-pygments\n");
				}
/*				if ( !strncmp(name, "asymptote", 9) ) {
					fprintf(fpack, "Provides: asymptote = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: asymptote < %%{tl_version}\n");
				}*/
				if ( !strncmp(name, "jadetex", 7) ) {
					fprintf(fpack, "Provides: jadetex = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: jadetex < %%{tl_version}\n");
				}
				fprintf(fpack, REQ_POSTTRANS"texlive-kpathsea-bin, tex-kpathsea\n");
				if ( pkg[i].exes ) {
					fprintf(fpack, REQ_POSTTRANS"texlive-tetex-bin, tex-tetex\n");
					fprintf(fpack, REQ_POST_POSTUN"texlive-tetex-bin, tex-tetex, tex-hyphen-base, texlive-base, texlive-texlive.infra\n");
				}
				/* require coreutils if there is %post scriptlet present */
				if ( pkg[i].exes || pkg[i].runfs ) fprintf(fpack, REQ_POST_POSTUN"coreutils\n");
//				if ( pkg[i].runfs ) fprintf(fpack, REQ_POST_POSTUN"texlive-kpathsea-bin, tex-kpathsea\n");
				for (n=0; n<pkg[i].reqs; n++) {
					if ( pkg[i].req[n] ) {
						if ( pkg[i].req[n]->catalogue_license & LIC_NOTALLOWED ) {
							continue;
						}
						if ( pkg[i].req[n]->reqs || pkg[i].req[n]->runfs || pkg[i].req[n]->exes ) {
							fprintf(fpack, "Requires: tex-%s\n", pkg[i].dep[n]);
							continue;
						}
#ifdef PACKAGE_DOCS
						if ( pkg[i].req[n]->docfs ) {
							fprintf(fpack, "Requires: tex-%s-doc\n", pkg[i].dep[n]);
							continue;
						}
#endif
#ifdef PACKAGE_SOURCE
						if ( pkg[i].req[n]->srcfs ) {
							fprintf(fpack, "Requires: tex-%s-source\n", pkg[i].dep[n]);
							continue;
						}
#endif
						if ( pkg[i].req[n]->binfs ) {
							size_t spost = strlen(pkg[i].dep[n])-5;
							if (strcmp(&pkg[i].dep[n][spost], ".ARCH")) {
								printf("Doesn't have .ARCH suffix!\n");
								exit(1);
							}
							pkg[i].dep[n][spost] = '\0';
							fprintf(fpack, "Requires: texlive-%s-bin\n", pkg[i].dep[n]);
							pkg[i].dep[n][spost] = '.';
							continue;
						}
					}
				}
				/* Ruby dependencies */
				for (n=0; n<pkg[i].runfs; n++) {
					if ( !strncmp(&pkg[i].runf[n][strlen(pkg[i].runf[n])-3], ".rb", 3)
					   ) {
						fprintf(fpack, "Requires: ruby\n");
						break;
					   }
				}
				/* Require needed files */
				for (n=0; n<pkg[i].file_reqs; n++) {
					fprintf(fpack, "Requires: tex(%s)\n", pkg[i].file_req[n]);
				}
				/* Provide all important files */
				for (n=0; n<pkg[i].file_provs; n++) {
					fprintf(fpack, "Provides: tex(%s) = %%{tl_version}\n", pkg[i].file_prov[n]);
				}
#ifdef FEDORA_FONTS
				/* check for fonts */
				for (n=0; n<pkg[i].runfs; n++) {
					size_t s = strlen(pkg[i].runf[n]);
					if (s > 4) {
						if (!strcmp(&pkg[i].runf[n][s-4], ".ttf") ||
						    !strcmp(&pkg[i].runf[n][s-4], ".ttc") ||
						    !strcmp(&pkg[i].runf[n][s-4], ".pfa") ||
						    !strcmp(&pkg[i].runf[n][s-4], ".pfb") ||
						    !strcmp(&pkg[i].runf[n][s-4], ".pcf") ||
						    !strcmp(&pkg[i].runf[n][s-4], ".otf")
						) {
							fprintf(fpack, "Requires: tex-%s-fedora-fonts\n", name);
							break;
						}
					}
				}
#endif
				/* write virtual provides */
				if ( !strcmp(name, "dvips") ) {
					fprintf(fpack, "Provides: tex(dvips) = %%{tl_version}, tetex-dvips = 3.1-99, texlive-texmf-dvips = %%{tl_version}, texlive-dvips = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: tetex-dvips < 3.1-99, texlive-texmf-dvips < %%{tl_version}\n");
					fprintf(fpack, "Requires: texlive-latex-fonts\n");
				}
				if ( !strcmp(name, "tex4ht") ) {
					fprintf(fpack, "Provides: tetex-tex4ht = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: tetex-tex4ht < %%{tl_version}\n");
				}
				if ( !strcmp(name, "latex") ) {
					fprintf(fpack, "Provides: tetex-latex = 3.1-99, texlive-texmf-latex = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: tetex-latex < 3.1-99, texlive-texmf-latex < %%{tl_version}\n");
				}
				if ( !strcmp(name, "IEEEtran") ) {
					fprintf(fpack, "Provides: tetex-IEEEtran = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: tetex-IEEEtran < %%{tl_version}\n");
				}
				if ( !strcmp(name, "bytefield") ) {
					fprintf(fpack, "Provides: tetex-bytefield = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: tetex-bytefield < %%{tl_version}\n");
				}
				if ( !strcmp(name, "elsevier") ) {
					fprintf(fpack, "Provides: tetex-elsevier = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: tetex-elsevier < %%{tl_version}\n");
				}
				if ( !strcmp(name, "perltex") ) {
					fprintf(fpack, "Provides: tetex-perltex = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: tetex-perltex < %%{tl_version}\n");
				}
				if ( !strcmp(name, "prosper") ) {
					fprintf(fpack, "Provides: tetex-prosper = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: tetex-prosper < %%{tl_version}\n");
				}
				if ( !strcmp(name, "texdoc") ) {
					fprintf(fpack, "Provides: texlive-doc = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: texlive-doc < %%{tl_version}\n");
				}
				if ( !strcmp(name, "pdfjam") ) {
					fprintf(fpack, "Provides: pdfjam = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: pdfjam < %%{tl_version}\n");
				}
				if ( !strcmp(name, "ptex") ) {
					fprintf(fpack, "Provides: mendexk = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: mendexk < %%{tl_version}\n");
				}
				if ( !strcmp(name, "japanese") ) {
					fprintf(fpack, "Provides: texlive-east-asian = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: texlive-east-asian < %%{tl_version}\n");
				}
				if ( !strcmp(name, "preview") ) {
					fprintf(fpack, "Provides: tex-preview = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: tex-preview < %%{tl_version}\n");
				}
/*				if ( !strcmp(name, "latexmk") ) {	// rhbz#868996
					fprintf(fpack, "Provides: latexmk = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: latexmk < %%{tl_version}\n");
				}*/
				if ( !strcmp(name, "chktex") ) {	/* rhbz#864211 */
					fprintf(fpack, "Provides: chktex = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: chktex < %%{tl_version}\n");
				}
				if ( !strcmp(name, "metauml") ) {	/* rhbz#573863 */
					fprintf(fpack, "Provides: metapost-metauml = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: metapost-metauml < %%{tl_version}\n");
				}
				if ( !strcmp(name, "cm-lgc") ) {	/* rhbz#907728 */
					fprintf(fpack, "Obsoletes: tex-cm-lgc < %%{tl_version}\n");
				}
				if ( !strcmp(name, "simplecv") ) {	/* rhbz#907728 */
					fprintf(fpack, "Obsoletes: tex-simplecv < %%{tl_version}\n");
				}
				if ( !strcmp(name, "kerkis") ) {	/* rhbz#907728 */
					fprintf(fpack, "Obsoletes: tex-kerkis < %%{tl_version}\n");
				}
				if ( !strcmp(name, "detex") ) {		/* rhbz#913678 */
					fprintf(fpack, "Obsoletes: detex < %%{tl_version}\n");
				}
				if ( !strcmp(name, "latexdiff") ) {	/* rhbz#913678 */
					fprintf(fpack, "Obsoletes: latexdiff < %%{tl_version}\n");
				}
				if ( !strcmp(name, "pdfjam") ) {	/* rhbz#913678 */
					fprintf(fpack, "Obsoletes: pdfbook < %%{tl_version}1212\n");
				}
				if ( !strcmp(name, "musixtex-fnts") ) {
					fprintf(fpack, "Provides: ctan-musixtex-fonts = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: ctan-musixtex-fonts < %%{tl_version}\n");
				}
				if ( !strcmp(name, "musixtex-doc") ) {
					fprintf(fpack, "Provides: tex-musixtex-doc = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: tex-musixtex-doc < %%{tl_version}\n");
				}
				if ( !strcmp(name, "musixtex") ) {
					fprintf(fpack, "Provides: tex-musixtex = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: tex-musixtex < %%{tl_version}\n");
				}
				if ( !strcmp(name, "dvipdfmx") ) {	/* rhbz#968358 */
					fprintf(fpack, "Provides: texlive-dvipdfm = 3:%%{tl_version}\n");
					fprintf(fpack, "Obsoletes: texlive-dvipdfm < 3:%%{tl_version}\n");
				}
				/* description */
#ifndef SRPMS
				fprintf(fpack, "\n%%description %s\n", name);
#else
				fprintf(fpack, "\n%%description\n");
#endif
				for (n=0; n<pkg[i].longdesc_lines; n++) {
					fprintf(fpack, "%s\n", pkg[i].longdesc[n]);
				}
				if ( !pkg[i].longdesc_lines ) fprintf(fpack, "%s package\n", name);
				if ( pkg[i].catalogue_date ) fprintf(fpack, "\ndate: %s\n", pkg[i].catalogue_date);
				fprintf(fpack, "\n");
				/* preun/post/postun scriptlets */
				if ( pkg[i].exes ) {
					int run_updmap, run_fmtutil;
#ifndef SRPMS
					fprintf(fpack, "%%post %s\n", name);
#else
					fprintf(fpack, "%%post\n");
#endif
					fprintf(fpack, "mkdir -p /var/run/texlive\ntouch /var/run/texlive/run-texhash\n");
					if ( pkg[i].has_info ) {
						int k;
						for (k=0; k<pkg[i].runfs; k++) {
							if (!strncmp(pkg[i].runf[k], "texmf-dist/doc/info/", 20)) {
								fprintf(fpack, "/sbin/install-info %%{_infodir}/%s %%{_infodir}/dir 2>/dev/null\n", &pkg[i].runf[k][20]);
							}
						}
					}
					fprintf(fpack, "if [ $1 -gt 0 ] ; then\n");
					for (run_updmap=run_fmtutil=n=0; n<pkg[i].exes; n++) {
						if ( !strncmp(pkg[i].exe[n], "addLuaMap ", 9) ) {
							continue;
						}
						if ( !strncmp(pkg[i].exe[n], "addMap ", 7) ) {
							fprintf(fpack, "%%{_bindir}/updmap-sys --quiet --nomkmap --enable Map=%s"REDIR, skipspaces(&pkg[i].exe[n][7]));
							run_updmap = 1;
							continue;
						}
						if ( !strncmp(pkg[i].exe[n], "addMixedMap ", 12) ) {
							fprintf(fpack, "%%{_bindir}/updmap-sys --quiet --nomkmap --enable MixedMap=%s"REDIR, skipspaces(&pkg[i].exe[n][12]));
							run_updmap = 1;
							continue;
						}
						if ( !strncmp(pkg[i].exe[n], "addKanjiMap ", 12) ) {
							fprintf(fpack, "%%{_bindir}/updmap-sys --quiet --nomkmap --enable KanjiMap=%s"REDIR, skipspaces(&pkg[i].exe[n][12]));
							run_updmap = 1;
							continue;
						}
						if ( !strncmp(pkg[i].exe[n], "BuildFormat ", 12) ) {
							fprintf(fpack, "%%{_bindir}/fmtutil-sys --enablefmt %s"REDIR, &pkg[i].exe[n][12]);
							run_fmtutil = 1;
							continue;
						}
						if ( !strncmp(pkg[i].exe[n], "AddFormat ", 10) ) {
							char *name	= strstr(pkg[i].exe[n], "name="),
							     *engine	= strstr(pkg[i].exe[n], "engine="),
							     *patterns	= strstr(pkg[i].exe[n], "patterns="),
							     *options	= strstr(pkg[i].exe[n], "options=");
							char *opt, opt_char;
							if ( !name || !engine || !options ) {
								fprintf(stderr, "Invalid AddFormat entry in package %s: '%s' '%s' '%s' '%s'.\n", pkg[i].name, name, engine, patterns, options);
								exit(1);
							}
							name += 5;
							engine += 7;
							if ( patterns ) patterns += 9;
							options += 8;
							*strchr(name, ' ') = '\0';
							*strchr(engine, ' ') = '\0';
							if ( patterns && strchr(patterns, ' ') ) *strchr(patterns, ' ') = '\0';
							if ( *options == '"' ) {
								options++;
								opt = strchr(options, '"');
							} else {
								for (opt=options; *opt != ' ' && *opt != '\n'; opt++);
							}
							opt_char = *opt;
							*opt = '\0';
							fprintf(fpack, "sed -i 's/^\\#\\!\\ %s.*$/%s %s %s %s/' %%{_texdir}/texmf-dist/web2c/fmtutil.cnf\n", name, name, engine, patterns?patterns:"-", options);
							name[strlen(name)] = ' ';
							engine[strlen(engine)] = ' ';
							if ( patterns ) patterns[strlen(patterns)] = ' ';
							*opt = opt_char;
							run_fmtutil = 1;
							continue;
						}
						if ( !strncmp(pkg[i].exe[n], "AddHyphen ", 10) ) {
							char *name		= strstr(pkg[i].exe[n], "name="),
							     *synonyms		= strstr(pkg[i].exe[n], "synonyms="),
							     *lefthyphenmin	= strstr(pkg[i].exe[n], "lefthyphenmin="),
							     *righthyphenmin	= strstr(pkg[i].exe[n], "righthyphenmin="),
							     *file		= strstr(pkg[i].exe[n], "file=");
							int k;
							if ( !name || !lefthyphenmin || !righthyphenmin || !file ) {
								fprintf(stderr, "Invalid AddHyphen entry in package %s.\n", pkg[i].name);
								exit(1);
							}
							name += 5;
							if ( synonyms ) synonyms += 9;
							lefthyphenmin += 14;
							righthyphenmin += 15;
							file += 5;
							for (k=10; pkg[i].exe[n][k]; k++) if ( pkg[i].exe[n][k] == ' ' ) pkg[i].exe[n][k] = '\0';
							fprintf(fpack, "sed -i '/%s.*/d' %%{_texdir}/texmf-dist/tex/generic/config/language.dat\n", name);
							fprintf(fpack, "echo \"%s %s\" >> %%{_texdir}/texmf-dist/tex/generic/config/language.dat\n", name, file);
							if ( synonyms ) {
								char *syn = synonyms, *s;
								while ( (s=strchr(syn, ',')) ) {
									*s = '\0';
									fprintf(fpack, "sed -i '/=%s/d' %%{_texdir}/texmf-dist/tex/generic/config/language.dat\n", syn);
									fprintf(fpack, "echo \"=%s\" >> %%{_texdir}/texmf-dist/tex/generic/config/language.dat\n", syn);
									*s = ',';
									syn = s+1;
								}
								fprintf(fpack, "sed -i '/=%s/d' %%{_texdir}/texmf-dist/tex/generic/config/language.dat\n", syn);
								fprintf(fpack, "echo \"=%s\" >> %%{_texdir}/texmf-dist/tex/generic/config/language.dat\n", syn);
							}
							fprintf(fpack, "sed -i '/\\\\addlanguage{%s}.*/d' %%{_texdir}/texmf-dist/tex/generic/config/language.def\n", name);
							fprintf(fpack, "echo \"\\addlanguage{%s}{%s}{}{%s}{%s}\" >> %%{_texdir}/texmf-dist/tex/generic/config/language.def\n", name, file, lefthyphenmin, righthyphenmin);
							if ( synonyms ) {
								char *syn = synonyms, *s;
								while ( (s=strchr(syn, ',')) ) {
									*s = '\0';
									fprintf(fpack, "sed -i '/\\\\addlanguage{%s}.*/d' %%{_texdir}/texmf-dist/tex/generic/config/language.def\n", syn);
									fprintf(fpack, "echo \"\\addlanguage{%s}{%s}{}{%s}{%s}\" >> %%{_texdir}/texmf-dist/tex/generic/config/language.def\n", syn, file, lefthyphenmin, righthyphenmin);
									*s = ',';
									syn = s+1;
								}
								fprintf(fpack, "sed -i '/\\\\addlanguage{%s}.*/d' %%{_texdir}/texmf-dist/tex/generic/config/language.def\n", syn);
								fprintf(fpack, "echo \"\\addlanguage{%s}{%s}{}{%s}{%s}\" >> %%{_texdir}/texmf-dist/tex/generic/config/language.def\n", syn, file, lefthyphenmin, righthyphenmin);
							}
							for (--k; k>=10; k--) if ( pkg[i].exe[n][k] == '\0' ) pkg[i].exe[n][k] = ' ';
							run_fmtutil = 1;
							continue;
						}
						fprintf(stderr, "Unknown exec format: %s\n", pkg[i].exe[n]);
						exit(1);
						continue;
					}
					if ( run_updmap ) fprintf(fpack, "touch /var/run/texlive/run-updmap\n");
					if ( run_fmtutil ) fprintf(fpack, "touch /var/run/texlive/run-fmtutil\n");
					fprintf(fpack, "fi\n:\n");
#ifndef SRPMS
					fprintf(fpack, "\n%%postun %s\n", name);
#else
					fprintf(fpack, "\n%%postun\n");
#endif
					fprintf(fpack, "if [ $1 == 0 ] ; then\n");
					for (run_updmap=n=0; n<pkg[i].exes; n++) {
						if ( !strncmp(pkg[i].exe[n], "addLuaMap", 9) ) {
							continue;
						}
						if ( !strncmp(pkg[i].exe[n], "addMap ", 7) ) {
							fprintf(fpack, "%%{_bindir}/updmap-sys --nomkmap --disable Map=%s"REDIR, skipspaces(&pkg[i].exe[n][7]));
							run_updmap = 1;
							continue;
						}
						if ( !strncmp(pkg[i].exe[n], "addMixedMap ", 12) ) {
							fprintf(fpack, "%%{_bindir}/updmap-sys --nomkmap --disable MixedMap=%s"REDIR, skipspaces(&pkg[i].exe[n][12]));
							run_updmap = 1;
							continue;
						}
						if ( !strncmp(pkg[i].exe[n], "addKanjiMap ", 12) ) {
							fprintf(fpack, "%%{_bindir}/updmap-sys --nomkmap --disable KanjiMap=%s"REDIR, skipspaces(&pkg[i].exe[n][12]));
							run_updmap = 1;
							continue;
						}
						if ( !strncmp(pkg[i].exe[n], "BuildFormat ", 12) ) {
							fprintf(fpack, "%%{_bindir}/fmtutil-sys --disablefmt %s"REDIR, &pkg[i].exe[n][12]);
							run_fmtutil = 1;
							continue;
						}
						if ( !strncmp(pkg[i].exe[n], "AddFormat ", 10) ) {
							char *name	= strstr(pkg[i].exe[n], "name="),
							     *engine	= strstr(pkg[i].exe[n], "engine="),
							     *patterns	= strstr(pkg[i].exe[n], "patterns="),
							     *options	= strstr(pkg[i].exe[n], "options=");
							char *opt, opt_char;
							if ( !name || !engine || !options ) {
								fprintf(stderr, "Invalid AddFormat entry in package %s: '%s' '%s' '%s' '%s'.\n", pkg[i].name, name, engine, patterns, options);
								exit(1);
							}
							name += 5;
							engine += 7;
							if ( patterns ) patterns += 9;
							options += 8;
							*strchr(name, ' ') = '\0';
							*strchr(engine, ' ') = '\0';
							if ( patterns ) *strchr(patterns, ' ') = '\0';
							if ( *options == '"' ) {
								options++;
								opt = strchr(options, '"');
							} else {
								for (opt=options; *opt != ' ' && *opt != '\n'; opt++);
							}
							opt_char = *opt;
							*opt = '\0';
							fprintf(fpack, "sed -i 's/^%s.*$/\\#\\!\\ %s %s %s %s/' %%{_texdir}/texmf-dist/web2c/fmtutil.cnf"REDIR, name, name, engine, patterns?patterns:"-", options);
							name[strlen(name)] = ' ';
							engine[strlen(engine)] = ' ';
							if ( patterns ) patterns[strlen(patterns)] = ' ';
							*opt = opt_char;
							run_fmtutil = 1;
							continue;
						}
						if ( !strncmp(pkg[i].exe[n], "AddHyphen ", 10) ) {
							char *name		= strstr(pkg[i].exe[n], "name="),
							     *synonyms		= strstr(pkg[i].exe[n], "synonyms="),
							     *lefthyphenmin	= strstr(pkg[i].exe[n], "lefthyphenmin="),
							     *righthyphenmin	= strstr(pkg[i].exe[n], "righthyphenmin="),
							     *file		= strstr(pkg[i].exe[n], "file=");
							int k;
							if ( !name || !lefthyphenmin || !righthyphenmin || !file ) {
								fprintf(stderr,"Invalid AddHyphen entry in package %s.\n", pkg[i].name);
								exit(1);
							}
							name += 5;
							if ( synonyms ) synonyms += 9;
							lefthyphenmin += 14;
							righthyphenmin += 15;
							file += 5;
							for (k=10; pkg[i].exe[n][k]; k++) if ( pkg[i].exe[n][k] == ' ' ) pkg[i].exe[n][k] = '\0';
							fprintf(fpack, "sed -i '/%s.*/d' %%{_texdir}/texmf-dist/tex/generic/config/language.dat"REDIR, name);
							if ( synonyms ) {
								char *syn = synonyms, *s;
								while ( (s=strchr(syn, ',')) ) {
									*s = '\0';
									fprintf(fpack, "  sed -i '/=%s/d' %%{_texdir}/texmf-dist/tex/generic/config/language.dat"REDIR, syn);
									*s = ',';
									syn = s+1;
								}
								fprintf(fpack, "  sed -i '/=%s/d' %%{_texdir}/texmf-dist/tex/generic/config/language.dat"REDIR, syn);
							}
							fprintf(fpack, "sed -i '/\\\\addlanguage{%s}.*/d' %%{_texdir}/texmf-dist/tex/generic/config/language.def"REDIR, name);
							if ( synonyms ) {
								char *syn = synonyms, *s;
								while ( (s=strchr(syn, ',')) ) {
									*s = '\0';
									fprintf(fpack, "sed -i '/\\\\addlanguage{%s}.*/d' %%{_texdir}/texmf-dist/tex/generic/config/language.def"REDIR, syn);
									*s = ',';
									syn = s+1;
								}
								fprintf(fpack, "sed -i '/\\\\addlanguage{%s}.*/d' %%{_texdir}/texmf-dist/tex/generic/config/language.def"REDIR, syn);
							}
							for (--k; k>=10; k--) if ( pkg[i].exe[n][k] == '\0' ) pkg[i].exe[n][k] = ' ';
							run_fmtutil = 1;
							continue;
						}
					}
					fprintf(fpack, "mkdir -p /var/run/texlive\ntouch /var/run/texlive/run-texhash\ntouch /var/run/texlive/run-mtxrun\n");
					if ( run_updmap ) fprintf(fpack, "touch /var/run/texlive/run-updmap\n");
					if ( run_fmtutil ) fprintf(fpack, "touch /var/run/texlive/run-fmtutil\n");
					fprintf(fpack, "fi\n:\n\n");
#ifndef SRPMS
					fprintf(fpack, "%%posttrans %s\n", name);
#else
					fprintf(fpack, "%%posttrans\n");
#endif
					fprintf(fpack, "if [ -e /var/run/texlive/run-texhash ]; then %%{_bindir}/texhash 2> /dev/null; rm -f /var/run/texlive/run-texhash; fi\n");
					if ( run_updmap ) fprintf(fpack, "if [ -e /var/run/texlive/run-updmap ]; then %%{_bindir}/updmap-sys --quiet --nomkmap &> /dev/null;rm -f /var/run/texlive/run-updmap; fi\n");
					if ( run_fmtutil ) fprintf(fpack, "if [ -e /var/run/texlive/run-fmtutil ]; then %%{_bindir}/fmtutil-sys --all &> /dev/null; rm -f /var/run/texlive/run-fmtutil; fi\n");
					fprintf(fpack, "if [ -e /var/run/texlive/run-mtxrun ]; then export TEXMF=/usr/share/texlive/texmf-dist; export TEXMFCNF=/usr/share/texlive/texmf-dist/web2c; export TEXMFCACHE=/var/lib/texmf; %%{_bindir}/mtxrun --generate &> /dev/null; rm -f /var/run/texlive/run-mtxrun; fi\n");
					fprintf(fpack, ":\n\n");
				} else if ( pkg[i].runfs ) {
#ifndef SRPMS
					fprintf(fpack, "%%post %s\n", name);
#else
					fprintf(fpack, "%%post\n");
#endif
					fprintf(fpack, "mkdir -p /var/run/texlive\ntouch /var/run/texlive/run-texhash\ntouch /var/run/texlive/run-mtxrun\n");
					if ( pkg[i].has_info ) {
						int k;
						for (k=0; k<pkg[i].runfs; k++) {
							if (!strncmp(pkg[i].runf[k], "texmf-dist/doc/info/", 20)) {
								fprintf(fpack, "/sbin/install-info %%{_infodir}/%s %%{_infodir}/dir 2>/dev/null\n", &pkg[i].runf[k][20]);
							}
						}
					}
					fprintf(fpack, ":\n");
#ifndef SRPMS
					fprintf(fpack, "\n%%postun %s\n", name);
#else
					fprintf(fpack, "\n%%postun\n");
#endif
					fprintf(fpack, "if [ $1 == 1 ]; then\n  mkdir -p /var/run/texlive\n  touch /var/run/run-texhash\nelse\n  %%{_bindir}/texhash 2> /dev/null\nfi\n");
					fprintf(fpack, ":\n\n");
#ifndef SRPMS
					fprintf(fpack, "%%posttrans %s\n", name);
#else
					fprintf(fpack, "%%posttrans\n");
#endif
					fprintf(fpack, "if [ -e /var/run/texlive/run-texhash ] && [ -e %%{_bindir}/texhash ]; then %%{_bindir}/texhash 2> /dev/null; rm -f /var/run/texlive/run-texhash; fi\n");
					fprintf(fpack, "if [ -e /var/run/texlive/run-mtxrun ]; then export TEXMF=/usr/share/texlive/texmf-dist; export TEXMFCNF=/usr/share/texlive/texmf-dist/web2c; export TEXMFCACHE=/var/lib/texmf; %%{_bindir}/mtxrun --generate &> /dev/null; rm -f /var/run/texlive/run-mtxrun; fi\n");
					fprintf(fpack, ":\n\n");
				}
				/* ... and main files */
#ifdef SRPMS
				mainpkg = 1;
#endif
				main_written = 0;
				append_filelist(pkg[i].name, "", pkg[i].runfs, pkg[i].runf, pkg[i].fedora_license?pkg[i].fedora_license:put_token(pkg[i].catalogue_license, license));
#ifdef SRPMS
				mainpkg = 0;
#endif
			}
			main_written = pkg[i].runfs || pkg[i].reqs || pkg[i].exes;
#ifdef PACKAGE_DOCS
			/* write doc package if exists */
			if ( pkg[i].docfs ) {
				pkg[i].any_pkg_written = 1;
				if ( !doc_expanded ) {
					fprintf(funpack, UNPACK" -dc %%{SOURCE%d} | tar x -C %%{buildroot}%%{_texdir}%s\n", srcno, pkg[i].reloc?"/texmf-dist":"");
					fprintf(fsrc, "Source%04d: "CTAN_URL"%s.doc.tar."UNPACK"\n", srcno++, name);
				}
				doc_expanded = 0;
#ifdef SRPMS
				if ( !main_written ) {
					fprintf(fpack, "Name: tex-%s-doc\n", name);
					fprintf(fpack, "Obsoletes: texlive-%s-doc\n", name);
					fprintf(fpack, "License: %s\n", pkg[i].fedora_license?pkg[i].fedora_license:(put_token(pkg[i].catalogue_license, spec_license)?put_token(pkg[i].catalogue_license, spec_license):"LPPL"));
				} else {
					fprintf(fpack, "%%package doc\n");
				}
#else
				fprintf(fpack, "%%package %s-doc\n", name);
#endif
				fprintf(fpack, "Summary: Documentation for %s\n", name);
				fprintf(fpack, "Version: %s\n", print_noarch_version(&pkg[i]));
				fprintf(fpack, "Release: %%{tl_noarch_release}\n");
				fprintf(fpack, "Provides: tex-%s-doc\n", name);
				fprintf(fpack, "BuildArch: noarch\nAutoReqProv: No\n");
				for (n=0; n<pkg[i].reqs; n++) {
					if ( !pkg[i].req[n] ) continue;
					if ( pkg[i].req[n]->catalogue_license & LIC_NOTALLOWED ) continue;
					if ( pkg[i].req[n]->docfs )
						fprintf(fpack, "Requires: tex-%s-doc\n", pkg[i].dep[n]);
				}
				if ( main_written ) {
#ifndef SRPMS
					fprintf(fpack, "\n%%description %s-doc\n", name);
#else
					fprintf(fpack, "\n%%description doc\n");
#endif
				} else {
#ifdef SRPMS
					fprintf(fpack, "\n%%description\n");
#else
					fprintf(fpack, "\n%%description %s-doc\n", name);
#endif
				}
				fprintf(fpack, "Documentation for %s\n\n", name);
#ifndef SRPMS
                                fprintf(fpack, "%%post %s-doc\n", name);
#else
                                fprintf(fpack, "%%post\n");
#endif
                                fprintf(fpack, "mkdir -p /var/run/texlive\ntouch /var/run/texlive/run-texhash\n");
                                fprintf(fpack, ":\n");
#ifndef SRPMS
                                fprintf(fpack, "\n%%postun %s-doc\n", name);
#else
                                fprintf(fpack, "\n%%postun\n");
#endif
                                fprintf(fpack, "if [ $1 == 1 ]; then\n  mkdir -p /var/run/texlive\n  touch /var/run/run-texhash\nelse\n  %%{_bindir}/texhash 2> /dev/null\nfi\n");
                                fprintf(fpack, ":\n\n");
#ifndef SRPMS
                                fprintf(fpack, "%%posttrans %s-doc\n", name);
#else
                                fprintf(fpack, "%%posttrans\n");
#endif
                                fprintf(fpack, "if [ -e /var/run/texlive/run-texhash ] && [ -e %%{_bindir}/texhash ]; then %%{_bindir}/texhash 2> /dev/null; rm -f /var/run/texlive/run-texhash; fi\n");
                                fprintf(fpack, ":\n\n");
				/* ... and doc files */
#ifdef SRPMS
				mainpkg = 1;
#endif
				append_filelist(pkg[i].name, "doc", pkg[i].docfs, pkg[i].docf, pkg[i].fedora_license?pkg[i].fedora_license:put_token(pkg[i].catalogue_license, license));
#ifdef SRPMS
				mainpkg = 0;
#endif
			}
#endif
#ifdef PACKAGE_SOURCE
			/* write source package if exists */
			if ( pkg[i].srcfs ) {
				fprintf(funpack, UNPACK" -dc %%{SOURCE%d} | tar x -C %%{buildroot}%%{_texdir}%s\n", srcno, pkg[i].reloc?"/texmf-dist":"");
				fprintf(fsrc, "Source%04d: "CTAN_URL"%s.source.tar."UNPACK"\n", srcno++, name);
#ifndef SRPMS
				fprintf(fpack, "%%package %s-source\n", name);
#else
				fprintf(fpack, "%%package source\n");
#endif
				fprintf(fpack, "Summary: Sources for %s\n", name);
				fprintf(fpack, "Version: %s\n", print_noarch_version(&pkg[i]));
				fprintf(fpack, "Release: %%{tl_noarch_release}\n");
				if ( strncmp(name, "kpathsea", 8) ) fprintf(fpack, "Requires: texlive-base\n");
				fprintf(fpack, "BuildArch: noarch\nAutoReqProv: No\n");
				for (n=0; n<pkg[i].reqs; n++) {
					if ( !pkg[i].req[n] ) continue;
					if ( pkg[i].req[n]->catalogue_license & LIC_NOTALLOWED ) continue;
					if ( pkg[i].req[n]->srcfs )
						fprintf(fpack, "Requires: tex-%s-source\n", pkg[i].dep[n]);
				}
#ifndef SRPMS
				fprintf(fpack, "\n%%description %s-source\n", name);
#else
				fprintf(fpack, "\n%%description source\n");
#endif
				fprintf(fpack, "Sources for %s\n\n", name);
				/* ... and src files */
#ifdef SRPMS
				mainpkg = 1;
#endif
				append_filelist(pkg[i].name, "source", pkg[i].srcfs, pkg[i].srcf, pkg[i].fedora_license?pkg[i].fedora_license:put_token(pkg[i].catalogue_license, license));
#ifdef SRPMS
				mainpkg = 0;
#endif
			}
#else
			/* write just link to source */
			if ( pkg[i].srcfs ) {
				fprintf(fsrc, "Source%04d: "CTAN_URL"%s.source.tar."UNPACK"\n", srcno++, name);
			}
#endif
#ifdef FEDORA_FONTS
			/* fonts */
			{
				int n, has_fonts = 0, k;
				for (n=0; n<pkg[i].runfs; n++) {
					size_t s = strlen(pkg[i].runf[n]);
					if (s > 4) {
						if (!strcmp(&pkg[i].runf[n][s-4], ".ttf") ||
						    !strcmp(&pkg[i].runf[n][s-4], ".ttc") ||
						    !strcmp(&pkg[i].runf[n][s-4], ".pfa") ||
						    !strcmp(&pkg[i].runf[n][s-4], ".pfb") ||
						    !strcmp(&pkg[i].runf[n][s-4], ".pcf") ||
						    !strcmp(&pkg[i].runf[n][s-4], ".otf")
						) {
							if ( !has_fonts ) {
#ifdef SRPMS
								fprintf(fpack, "%%package fedora-fonts\n");
#else
								fprintf(fpack, "%%package %s-fedora-fonts\n", name);
#endif
								fprintf(fpack, "Summary: Fonts for %s\n", name);
								fprintf(fpack, "Version: %s\n", print_noarch_version(&pkg[i]));
								fprintf(fpack, "Release: %%{tl_noarch_release}\n");
								fprintf(fpack, "Requires: fontpackages-filesystem\n");
								fprintf(fpack, "BuildRequires: fontpackages-devel\n");
								fprintf(fpack, "Requires: tex-%s\n", name);
								fprintf(fpack, "BuildArch: noarch\n");
#ifdef SRPMS
								fprintf(fpack, "\n%%description fedora-fonts\n");
#else
								fprintf(fpack, "\n%%description %s-fedora-fonts\n", name);
#endif
								for (k=0; k<pkg[i].longdesc_lines; k++) {
									fprintf(fpack, "%s\n", pkg[i].longdesc[k]);
								}
								if ( !pkg[i].longdesc_lines ) fprintf(fpack, "Fonts for %s package.\n", name);
								if ( pkg[i].catalogue_date ) fprintf(fpack, "\ndate: %s\n", pkg[i].catalogue_date);
								fprintf(fpack, "\n");
								fprintf(ffont, "\n# link installed fonts with Fedora\n");
								fprintf(ffont, "install -d -m 0755 %%{buildroot}%%{_fontdir}\n");
								fprintf(ffont, "pushd %%{buildroot}%%{_fontdir}\n");
#ifdef SRPMS
								fprintf(ffile, "%%files fedora-fonts\n");
#else
								fprintf(ffile, "%%files %s-fedora-fonts\n", name);
#endif
								fprintf(ffile, "%%defattr(-,root,root)\n%%dir %%{_fontdir}\n");
							}
							has_fonts = 1;
							for (--s; pkg[i].runf[n][s] != '/'; s--);
							fprintf(ffont, "mv %%{buildroot}%%{_texdir}/%s .\n", pkg[i].runf[n]);
							fprintf(ffont, "ln -s %%{_fontdir}%s %%{buildroot}%%{_texdir}/%s\n", &pkg[i].runf[n][s], pkg[i].runf[n]);
							fprintf(ffile, "%%{_fontdir}%s\n", &pkg[i].runf[n][s]);
							printf("%%{_fontdir}%s\n", &pkg[i].runf[n][s]);
						}
					}
				}
				if ( has_fonts ) {
					fprintf(ffont, "popd\n");
#ifdef SRPMS
					fprintf(ffont, "%%_font_pkg -n fedora *\n");
#endif
				}
			}
#endif
#ifdef SRPMS
			if (pkg[i].has_man) {
				fprintf(fremove, "mkdir -p %%{buildroot}/%%{_datadir}/\n");
				fprintf(fremove, "mv %%{buildroot}/%%{_texdir}/texmf-dist/doc/man %%{buildroot}/%%{_datadir}/\n");
			}
			if (pkg[i].has_info) {
				fprintf(fremove, "mkdir -p %%{buildroot}/%%{_infodir}/\n");
				fprintf(fremove, "mv %%{buildroot}/%%{_texdir}/texmf-dist/doc/info/* %%{buildroot}/%%{_infodir}/\n");
			}
#endif
#ifdef SRPMS
			if ( !pkg[i].binfs ) {
				fclose(ffont);
				fclose(fremove);
				fclose(fsrc);
				fclose(funpack);
				fclose(ffile);
				fclose(fpack);
				fpack = ofpack;
				ffile = offile;
				funpack = ofunpack;
				fsrc = ofsrc;
				fremove = ofremove;
				ffont = offont;
			}
#endif
			if ( pkg[i].binfs && (has_noarch_pkg || pkg[i].binfs > 1) ) {
				char *ar = strstr(name, ".ARCH");
				pkg[i].any_pkg_written = 1;
				*ar = '\0';
				fprintf(fpack, "%%package %s-bin\n", name);
				fprintf(fpack, "Summary: Binaries for %s\n", name);
				fprintf(fpack, "Version: %s\n", print_noarch_version(&pkg[i]));
				if ( strncmp(name, "kpathsea", 8) ) fprintf(fpack, "Requires: texlive-base\n");
				if ( has_noarch_pkg ) fprintf(fpack, "Requires: texlive-%s\n", name);
				if ( !strcmp(name, "xetex") ) {
					fprintf(fpack, "Requires: teckit\n");
					fprintf(fpack, "Provides: xdvipdfmx = %%{version}-%%{release}\n");
					fprintf(fpack, "Obsoletes: xdvipdfmx < %%{version}-%%{release}\n");
				}
				if ( !strcmp(name, "dvipdfmx") ) {
					fprintf(fpack, "Provides: dvipdfmx = %%{tl_version}, dvipdfm = %%{tl_version}, texlive-dvipdfm-bin = 3:%%{tl_version}\n");
					fprintf(fpack, "Obsoletes: dvipdfmx < %%{tl_version}, dvipdfm < %%{tl_version}, texlive-dvipdfm-bin < 3:%%{tl_version}\n");
				}
				if ( !strcmp(name, "xdvi") ) {
					fprintf(fpack, "Provides: xdvi = %%{tl_version}, xdvik = %%{tl_version}, tetex-xdvi = 3.1-99\n");
					fprintf(fpack, "Obsoletes: xdvi < %%{tl_version}, xdvik < %%{tl_version}, tetex-xdvi < 3.1-99\n");
				}
				if ( !strcmp(name, "dvipng") ) {
					fprintf(fpack, "Provides: dvipng = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: dvipng < %%{tl_version}\n");
				}
				if ( !strcmp(name, "pdfcrop") ) {
					fprintf(fpack, "Requires: ghostscript-devel\n");
				}
				if ( !strcmp(name, "dvisvgm") ) {
					fprintf(fpack, "Provides: dvisvgm = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: dvisvgm < %%{tl_version}\n");
				}
				if ( !strcmp(name, "lcdftypetools") ) {
					fprintf(fpack, "Provides: lcdf-typetools = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: lcdf-typetools < %%{tl_version}\n");
				}
				if ( !strcmp(name, "xmltex") ) {
					fprintf(fpack, "Provides: xmltex = %%{tl_version}0101\n");
					fprintf(fpack, "Obsoletes: xmltex < %%{tl_version}0101\n");
				}
				if ( !strcmp(name, "pstools") ) {
					fprintf(fpack, "Provides: ps2eps = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: ps2eps < %%{tl_version}\n");
				}
/*				if ( !strcmp(name, "asymptote") ) {
					fprintf(fpack, "Provides: asymptote = %%{tl_version}\n");
					fprintf(fpack, "Obsoletes: asymptote < %%{tl_version}\n");
				}*/
				printf("bin-package %s contains %d files\n", pkg[i].name, pkg[i].binfs);
				{
					int n, noarch = 1;
					char s[0x100];
					for (n=0; n<pkg[i].binfs; n++) {
						FILE *f;
						struct stat sb;
						snprintf(s, sizeof(s), "texlive.expanded/%s", pkg[i].binf[n]);
						lstat(s, &sb);
						if ((sb.st_mode&S_IFMT) == S_IFLNK) continue;
						if ( (f=fopen(s,"rb")) ) {
							unsigned char d[4];
							fread(d, 4, 1, f);
							fclose(f);
							if ( d[0] == 0x7f && d[1] == 0x45 && d[2] == 0x4c && d[3] == 0x46 ) {
								noarch = 0;
								break;
							}
						} else {
							printf("Unable to open: %s\n", s);
							exit(1);
						}
					}
					fprintf(fpack, "Release: %%{tl_release}\n");
					if ( noarch ) {
						fprintf(fpack, "BuildArch: noarch\n");
					} else {
						fprintf(fpack, "Requires: texlive-kpathsea-lib%%{?_isa} = %%{epoch}:%%{tl_version}\n");
					}
				}
				fprintf(fpack, "\n%%description %s-bin\n", name);
				fprintf(fpack, "Binaries for %s\n\n", name);
				*ar = '.';
				/* ... and add bin files */
				{
					char s[0x100], *lic_name = NULL;
					int ii, lic_code = LIC_LPPL;
					unsigned long h;
					strcpy(s, pkg[i].name);
					*strstr(s,".ARCH") = 0;
					h = hash(s);
					for (ii=0; ii<p; ii++) {
						if ( pkg[ii].namehash == h && !strcmp(pkg[ii].name, s)) {
							lic_code = pkg[ii].catalogue_license?pkg[ii].catalogue_license:LIC_LPPL;
							lic_name = pkg[ii].fedora_license;
							break;
						}
					}
					append_filelist(pkg[i].name, "", pkg[i].binfs, pkg[i].binf, lic_name?lic_name:put_token(lic_code, license));
				}
			}
slv:
			for (n=0; n<pkg[i].reqs; n++) {
				solve(pkg[i].dep[n]);
			}
			level--;
			found = 1;
			break;
		}
	}
	if ( !found ) fprintf(stderr, "Unknown dep: %s\n", name);
}
void gen_obsoletes() {
	size_t i, op = sizeof(old_pkgs)/sizeof(old_pkgs[0]);
	FILE *fobs = fopen("_obsoletes.spec","wt");
	for (i=0; i<op; i++) {
		size_t n, fnd=0;
		unsigned long h = hash(old_pkgs[i]);
		for (n=0; n<p; n++) {
			if (h == pkg[n].namehash && !strcmp(pkg[n].name, old_pkgs[i]) && pkg[n].any_pkg_written) {
				fnd = 1;
				break;
			}
		}
		if (!fnd) {
			fprintf(fobs,"Obsoletes: texlive-%s <= 3:%%{tl_version}\n", old_pkgs[i]);
			if (strncmp(old_pkgs[i], "collection-", 11)) {
				fprintf(fobs,"Obsoletes: texlive-%s-bin <= 3:%%{tl_version}\n", old_pkgs[i]);
				fprintf(fobs,"Obsoletes: texlive-%s-doc <= 3:%%{tl_version}\n", old_pkgs[i]);
				fprintf(fobs,"Obsoletes: texlive-%s-fedora-fonts <= 3:%%{tl_version}\n", old_pkgs[i]);
			}
		}
	}
	fclose(fobs);
}
int main() {
	FILE *f = fopen("texlive.tlpdb","rt");
	if ( !f ) {
		fprintf(stderr, "Unable to open TeX Live package database\n");
		return 1;
	}
	fseek(f,0,SEEK_END);
	size=ftell(f);
	fseek(f,0,SEEK_SET);
	m=malloc(size);
	if ( fread(m, size, 1, f) != 1 ) {
		fprintf(stderr,"Error reading TeX Live package database\n");
		return 1;
	}
	parse();
	{
		int i, n;
		for (i=0; i<p; i++) {
			for (n=0; n<pkg[i].reqs; n++) {
				if ( pkg[i].req[n] ) continue;
				{
					int x, y, found = 0;
					unsigned long h;
					package *pk = NULL;
					char *depname = pkg[i].dep[n];
					h = hash(depname);
					for (x=0; x<p; x++) {
						if ( pkg[x].namehash == h && !strcmp(pkg[x].name, depname) ) {
							pk = &pkg[x];
							found = 1;
							break;
						}
					}
					if ( !found ) {
						fprintf(stderr, "Unknown dependency: %s\n", depname);
						continue;
					}
					for (x=0; x<p; x++) {
						for (y=0; y<pkg[x].reqs; y++) {
							if ( !strcmp(pkg[x].dep[y], pk->name) ) {
								pkg[x].req[y] = pk;
							}
						}
					}
				}
			}
		}
#ifdef SRPMS
		system("rm -rf ./specs; mkdir specs");
#endif
		fill_file_reqprov();
		for (i=0; i<p; i++) solve(pkg[i].name);
	}
	gen_obsoletes();
	{
		int i, n, ndirs;
		FILE *fdirs = fopen("_dirs.spec","wt");
#ifdef SRPMS
		FILE *fmkdirs = fopen("_mkdirs.spec","wt");
#endif
		ndirs = dirs;
		for ( i=0; i<ndirs; i++ ) {
			char *end, *d;
			int pass;
			if ( !strncmp(dir[i].dir, "bin/", 4) || !strncmp(dir[i].dir, "tlpkg/", 6) || dir[i].pkgs < 1 ) continue;
			for ( pass=n=0; n<dir[i].pkgs; n++ ) {
				if ( !(dir[i].lic[0]&LIC_NOTALLOWED) ) {
					pass = 1;
					break;
				}
			}
			if ( !pass ) continue;
			if ( !(strstr(dir[i].pkg[0], "win32") || strstr(dir[i].dir, "win32")) ) {
				fprintf(fdirs, "%%dir %%{_texdir}/%s\n", dir[i].dir);
#ifdef SRPMS
				fprintf(fmkdirs, "mkdir -p %%{buildroot}%%{_texdir}/%s\n", dir[i].dir);
#endif
			} else continue;
			d = strdup(dir[i].dir);
			while ( (end=strrchr(d, '/')) ) {
				unsigned long h;
				*end = '\0';
				h = hash(d);
				for ( n=0; n<dirs; n++ ) {
					if ( h == dir[n].dirhash && !strcmp(d, dir[n].dir) ) {
						goto done;
					}
				}
				dirs++;
				dir = realloc(dir, dirs*sizeof(dir_type));
				dir[dirs-1].dir = strdup(d);
				dir[dirs-1].dirhash = h;
				dir[dirs-1].pkgs = 0;
				fprintf(fdirs, "%%dir %%{_texdir}/%s\n", d);
			}
done:
			free(d);
		}
#ifdef SRPMS
		fclose(fmkdirs);
#endif
		fclose(fdirs);
	}
	fclose(fpack);
	fclose(ffile);
	fclose(funpack);
	fclose(fsrc);
	fclose(fremove);
	fclose(ffont);
	return 0;
}