summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/splitindex/splitindex.c
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/splitindex/splitindex.c')
-rw-r--r--macros/latex/contrib/splitindex/splitindex.c602
1 files changed, 602 insertions, 0 deletions
diff --git a/macros/latex/contrib/splitindex/splitindex.c b/macros/latex/contrib/splitindex/splitindex.c
new file mode 100644
index 0000000000..515799cba9
--- /dev/null
+++ b/macros/latex/contrib/splitindex/splitindex.c
@@ -0,0 +1,602 @@
+/*
+ * splitindex.c
+ * Copyright (c) Markus Kohm, 2002
+ *
+ * $Id: splitindex.c 4 2016-02-18 10:13:32Z mjk $
+ *
+ * This file is part of the SplitIndex bundle.
+ *
+ * This work may be distributed and/or modified under the conditions of
+ * the LaTeX Project Public License, version 1.3c of the license.
+ * The latest version of this license is in
+ * http://www.latex-project.org/lppl.txt
+ * and version 1.3c or later is part of all distributions of LaTeX
+ * version 2005/12/01 or later and of this work.
+ *
+ * This work has the LPPL maintenance status "author-maintained".
+ *
+ * The Current Maintainer and author of this work is Markus Kohm.
+ *
+ * The list of all files belongig to the SplitIndex bundle is given in
+ * in the file `manifest.txt'. Files generated by means of unpacking the
+ * distribution (using, for example, the docstrip program) or by means
+ * of compiling them from a source file, for example, from splitindex.c
+ * or splitindex.java may be distributed at the distributor's discretion.
+ * However if they are distributed then a copy of the SplitIndex bundle
+ * must be distributed together with them.
+ *
+ * The list of derived (unpacked or compiled) files belongig to the
+ * distribution and covered by LPPL is defined by the unpacking scripts
+ * (with extension .ins) and the installation script (with name
+ * install.sh) which are part of the distribution.
+ *
+ * Two often ignorred clauses from LPPL 1.3c you should not ignore:
+ * ----------------------------------------------------------------
+ * 2. You may distribute a complete, unmodified copy of the Work as you
+ * received it. Distribution of only part of the Work is considered
+ * modification of the Work, and no right to distribute such a Derived
+ * Work may be assumed under the terms of this clause.
+ * 3. You may distribute a Compiled Work that has been generated from a
+ * complete, unmodified copy of the Work as distributed under Clause 2
+ * above, as long as that Compiled Work is distributed in such a way that
+ * the recipients may install the Compiled Work on their system exactly
+ * as it would have been installed if they generated a Compiled Work
+ * directly from the Work.
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <regex.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+enum {
+ OPT_HELP = 'h', OPT_MAKEINDEX = 'm', OPT_IDENTIFY = 'i',
+ OPT_RESULTIS = 'r', OPT_VERBOSE = 'v', OPT_SUFFIXIS = 's',
+ OPT_VERSION = 'V'
+};
+
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined (NO_LONGOPT)
+
+#define HAS_LONGOPT 0
+#define HAPAR ""
+
+#else /* defined(__OpenBSD__) || defined(__FreeBSD__) || defined(NO_LONGOPT) */
+
+#define HAS_LONGOPT 1
+#define HAPAR "\n\t\t"
+
+#include <getopt.h>
+
+static const struct option long_options[] = {
+ { "help", 0, NULL, OPT_HELP },
+ { "makeindex", 1, NULL, OPT_MAKEINDEX },
+ { "identify", 1, NULL, OPT_IDENTIFY },
+ { "resultis", 1, NULL, OPT_RESULTIS },
+ { "suffixis", 1, NULL, OPT_SUFFIXIS },
+ { "verbose", 0, NULL, OPT_VERBOSE },
+ { "version", 0, NULL, OPT_VERSION },
+ { NULL, 0, NULL, 0 },
+};
+
+#endif
+
+static const char short_options[] = {
+ OPT_HELP,
+ OPT_MAKEINDEX, ':',
+ OPT_IDENTIFY, ':',
+ OPT_RESULTIS, ':',
+ OPT_SUFFIXIS, ':',
+ OPT_VERBOSE,
+ OPT_VERSION,
+};
+
+int Verbose = 0;
+
+char *MakeIndex = "makeindex";
+char *Identify = "^(\\\\indexentry)\\[([^]]*)\\](.*)$";
+char *ResultIs = "$1$3";
+char *SuffixIs = "-$2";
+char *IDX = NULL;
+char *Jobname = NULL;
+char * const * MakeIndexArgs = NULL;
+char *prgname = "splitindex";
+int MakeIndexArgc = 0;
+
+static void show_version( void ) {
+ printf( "splitindex 0.2a\n"
+ "Copyright (c) 2002 Markus Kohm <kohm@gmx.de>\n" );
+}
+
+static void show_usage( FILE *out ) {
+ fputs( "Usage: splitindex [OPTION]... RAWINDEXFILE [MAKEINDEXOPTION]...\n",
+ out );
+}
+
+static void usage_error( const char *format, ... ) {
+ if ( format != NULL ) {
+ va_list ap;
+ va_start( ap, format );
+ vfprintf( stderr, format, ap );
+ va_end( ap );
+ }
+ fputs( "Try `splitindex "
+#if HAS_LONGOPT
+ "--help"
+#else
+ "-h"
+#endif
+ "' for more information.\n", stderr );
+ exit( 1 );
+}
+
+static void show_help( void ) {
+ show_version();
+ printf( "\n" );
+ show_usage( stdout );
+ printf(
+ "Split a single raw index file into multiple raw index files.\n"
+ "Example: splitindex.pl foo.idx.\n"
+ "\n"
+ "Options:\n"
+ " -h"
+#if HAS_LONGOPT
+ ", --help "
+#else
+ " "
+#endif
+ "\tshow this help and terminate\n"
+ " -m"
+#if HAS_LONGOPT
+ ", --makeindex"
+#endif
+ " PROGNAME " HAPAR
+ "\tcall PROGNAME instead of default `%s'.\n",
+ MakeIndex
+ );
+ printf(
+ " -i"
+#if HAS_LONGOPT
+ ", --identify"
+#endif
+ " EXPRESSION " HAPAR
+ "\tuse regular EXPRESSION to match entries\n"
+ "\t\t\t(see also option --resultis and --suffixis).\n"
+ "\t\t\tDefault is `%s'.\n",
+ Identify
+ );
+ printf(
+ " -r"
+#if HAS_LONGOPT
+ ", --resultis"
+#endif
+ " PATTERN " HAPAR
+ "\tcreate line to be written from PATTERN after matching\n"
+ "\t\t\tlines (see also option --identify).\n"
+ "\t\t\tDefault is `%s'.\n",
+ ResultIs
+ );
+ printf(
+ " -s"
+#if HAS_LONGOPT
+ ", --suffixis"
+#endif
+ " PATTERN " HAPAR
+ "\tcreate suffix to be used from PATTERN after matching\n"
+ "\t\t\tlines (see also option --identify).\n"
+ "\t\t\tDefault is `%s'.\n",
+ SuffixIs
+ );
+ printf(
+ " -v"
+#if HAS_LONGOPT
+ ", --verbose "
+#else
+ " "
+#endif
+ "\tbe more verbose\n"
+ "\t\t\t(can be used multiple to increase verbosity)\n"
+ " -V"
+#if HAS_LONGOPT
+ ", --version "
+#else
+ " "
+#endif
+ "\tshow version and terminate\n"
+ );
+ exit(0);
+}
+
+static void ScanArguments( int argc, char * const argv[] ) {
+ int retVal;
+ char *hs;
+ if ( argc > 0 )
+ prgname = argv[0];
+#if HAS_LONGOPT
+ while ( ( retVal = getopt_long( argc, argv, short_options,
+ long_options, NULL ) ) != - 1 ) {
+#else
+ while ( ( retVal = getopt( argc, argv, short_options ) ) != - 1 ) {
+#endif
+ switch( retVal ) {
+ case OPT_HELP:
+ show_help();
+ break; /* should never be reached */
+ case OPT_VERSION:
+ show_version();
+ exit( 0 );
+ break; /* should never be reached */
+ case OPT_MAKEINDEX:
+ MakeIndex = optarg;
+ break;
+ case OPT_IDENTIFY:
+ Identify = optarg;
+ break;
+ case OPT_RESULTIS:
+ ResultIs = optarg;
+ break;
+ case OPT_SUFFIXIS:
+ SuffixIs = optarg;
+ break;
+ case OPT_VERBOSE:
+ Verbose++;
+ break;
+ case ':':
+ case '?':
+ usage_error( NULL );
+ break; /* should never be reached */
+ }
+ }
+ if ( optind < argc ) {
+ IDX = argv[optind++];
+ MakeIndexArgc = argc - optind;
+ MakeIndexArgs = argv + optind;
+ } else {
+ usage_error( "missing raw index file\n" );
+ return; /* should never be reached */
+ }
+
+ if ( ( Jobname = strdup( IDX ) ) == NULL ) {
+ perror( prgname );
+ exit( errno );
+ }
+
+ if ( ( ( hs = strrchr( Jobname, '.' ) ) != NULL )
+ && !strcmp( hs, ".idx" ) )
+ *hs = 0;
+}
+
+static char *regsub( const char *string, const char *replace,
+ int nmatch, regmatch_t pmatch[] ) {
+ int pass;
+ int size, n;
+ const char *hs;
+ char c;
+ char *retVal = NULL;
+ char *ts;
+
+ /* Two times parsing to get size and replace */
+ for ( pass = size = 0; pass < 2; pass++ ) {
+ ts = retVal;
+ for ( hs = replace; *hs; hs++ ) {
+ switch( *hs ) {
+ case '$':
+ if ( isdigit( hs[1] ) ) {
+ n = *++hs - '0';
+ if ( ( pmatch[n].rm_so >= 0 )
+ && ( pmatch[n].rm_so < pmatch[n].rm_eo ) ) {
+ /* maybe group n is not empty */
+ if ( pass ) {
+ strncpy( ts,
+ string + pmatch[n].rm_so,
+ pmatch[n].rm_eo - pmatch[n].rm_so );
+ ts += pmatch[n].rm_eo - pmatch[n].rm_so;
+ } else {
+ size += pmatch[n].rm_eo - pmatch[n].rm_so;
+ }
+ }
+ } else {
+ if ( pass ) {
+ *ts++ = '$';
+ } else {
+ size++;
+ }
+ }
+ break;
+ case '\\':
+ switch( c = *++hs ) {
+ case 0: c = '\\'; hs--; break;
+ case 'b': c = '\b'; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ }
+ if ( pass ) {
+ *ts++ = c;
+ } else {
+ size++;
+ }
+ break;
+ default:
+ if ( pass ) {
+ *ts++ = *hs;
+ } else {
+ size++;
+ }
+ break;
+ }
+ }
+ if ( pass ) {
+ *ts = '\0';
+ } else {
+ if ( ( retVal = malloc( size + 1 ) ) == NULL ) {
+ perror( prgname );
+ exit( 1 );
+ }
+ }
+ }
+
+ return retVal;
+}
+
+static struct list {
+ struct list *next;
+ char *name;
+ FILE *file;
+} *IDXfiles = NULL;
+
+static FILE *findsuffix( const char *name ) {
+ struct list *run;
+ for ( run = IDXfiles;
+ run != NULL;
+ run = run->next ) {
+ const char *suffix = strchr( run->name, '\0' );
+ suffix -= 4; /* .idx */
+ suffix -= strlen( name );
+ if ( ( suffix >= run->name )
+ && !strncmp( suffix, name, strlen( name ) ) ) {
+ return run->file;
+ }
+ }
+ return NULL;
+}
+
+static struct list *addentry( char *name, FILE *file ) {
+ struct list *newentry = malloc( sizeof( struct list ) );
+ if ( !newentry ) {
+ perror( prgname );
+ exit( 1 );
+ }
+ newentry->name = name;
+ newentry->file = file;
+ if ( IDXfiles == NULL ) {
+ newentry->next = NULL;
+ } else {
+ newentry->next = IDXfiles;
+ }
+ IDXfiles = newentry;
+ return IDXfiles;
+}
+
+static FILE *newentry( const char *suffix ) {
+ char *name;
+ FILE *file;
+
+ if ( ( name = malloc( strlen( Jobname ) + strlen( suffix ) + 5 ) ) == NULL ) {
+ perror( prgname );
+ exit( 1 );
+ }
+
+ strcpy( name, Jobname );
+ strcat( name, suffix );
+ strcat( name, ".idx" );
+
+ if ( ( file = fopen( name, "w" ) ) == NULL ) {
+ perror( name );
+ exit( errno );
+ }
+
+ if ( Verbose > 1 )
+ printf( "New index file %s\n", name );
+ addentry( name, file );
+ return file;
+}
+
+static void CloseAllIDX( void ) {
+ struct list *run;
+ for ( run = IDXfiles; run != NULL; run = run->next )
+ if ( fclose( run->file ) ) {
+ perror( run->name );
+ exit( 1 );
+ }
+}
+
+static void CallMakeIndex( void ) {
+ char **argv;
+ int idx;
+ struct list *run, *next;
+
+ if ( ( argv = calloc( MakeIndexArgc + 3, sizeof( char * ) ) ) == NULL ) {
+ perror( prgname );
+ exit( 0 );
+ }
+
+ for ( idx = 0; idx < MakeIndexArgc; idx++ )
+ argv[idx+1] = MakeIndexArgs[idx];
+
+ idx++;
+ argv[0] = MakeIndex;
+
+ for ( run = IDXfiles; run != NULL; run = next ) {
+ pid_t fret;
+ int status;
+ argv[idx] = run->name;
+
+ if ( ( fret = fork() ) == 0 ) {
+ /* This is the child */
+ if ( Verbose > 1 ) {
+ int i;
+ for ( i = 0; argv[i] != NULL; i++ )
+ printf( "\"%s\" ", argv[i] );
+ printf( "\n" );
+ }
+ if ( execvp( MakeIndex, argv ) ) {
+ perror( MakeIndex );
+ exit( 1 );
+ }
+ } else if ( fret == -1 ) {
+ perror( prgname );
+ exit( 1 );
+ } else {
+ /* Parent */
+ waitpid( fret, &status, 0 );
+ if ( ! WIFEXITED( status ) ) {
+ fprintf( stderr, "%s terminated abnormally!\n", MakeIndex );
+ exit( 1 );
+ }
+ }
+
+ free( (void *)run->name );
+ next = run->next;
+ free( run );
+ }
+
+
+}
+
+static void ProcessIDXFile( void ) {
+ FILE *fIDX;
+ char *line;
+ regex_t preg;
+ int retVal;
+ int buffersize = 2050;
+ regmatch_t pmatch[10];
+
+ if ( ( line = malloc( buffersize ) ) == NULL ) {
+ perror( prgname );
+ exit( errno );
+ }
+
+ if ( ( retVal = regcomp( &preg, Identify, REG_EXTENDED ) ) != 0 ) {
+ regerror( retVal, &preg, line, buffersize );
+ fprintf( stderr, "Error at identify: %s\n", line );
+ free( line );
+ exit( 1 );
+ }
+
+ if ( ( fIDX = fopen( IDX, "r" ) ) == NULL ) {
+ if ( !strcmp ( IDX, Jobname ) ) {
+ if ( ( IDX = malloc( strlen( Jobname + 5 ) ) ) == NULL ) {
+ perror( prgname );
+ regfree( &preg );
+ free( line );
+ exit( errno );
+ }
+ strcpy( IDX, Jobname );
+ strcat( IDX, ".idx" );
+ if ( ( fIDX = fopen( IDX, "r" ) ) == NULL ) {
+ fprintf( stderr,
+ "Can read neither file %s nor file %s\n",
+ Jobname, IDX );
+ regfree( &preg );
+ free( line );
+ exit( 1 );
+ }
+ } else {
+ fprintf( stderr,
+ "Can't red file %s\n", IDX );
+ regfree( &preg );
+ free( line );
+ exit( 1 );
+ }
+ }
+
+ while ( fgets( line, buffersize, fIDX ) != NULL ) {
+ char *hs;
+ char *result, *suffix;
+ FILE *f;
+ while ( ( ( hs = strchr( line, '\n' ) ) == NULL )
+ && ! feof( fIDX ) ) {
+ if ( ( line = realloc( line, 2 * buffersize ) ) == NULL ) {
+ perror( prgname );
+ exit( errno );
+ }
+ if ( fgets( line + buffersize - 1, buffersize + 1, fIDX ) == NULL )
+ break;
+ buffersize *= 2;
+ }
+ if ( ferror( fIDX ) )
+ break;
+ if ( ( hs = strchr( line, '\n' ) ) != NULL ) // remove newline
+ *hs = 0;
+ if ( ( retVal = regexec( &preg, line, 10, pmatch, 0 ) ) == 0 ) {
+ result = regsub( line, ResultIs, 10, pmatch );
+ suffix = regsub( line, SuffixIs, 10, pmatch );
+ } else {
+ int i;
+ result = strdup( line );
+ for ( i = 0; i < 10; i++ ) {
+ pmatch[i].rm_so = 0;
+ pmatch[i].rm_eo = 3;
+ }
+ suffix = regsub( "idx", SuffixIs, 10, pmatch );
+ }
+ if ( !result || !suffix ) {
+ perror( prgname );
+ exit ( 1 );
+ }
+
+ if ( ( f = findsuffix( suffix ) ) == NULL )
+ f = newentry( suffix );
+ fprintf( f, "%s\n", result );
+
+ free( suffix );
+ free( result );
+ }
+
+ regfree( &preg );
+ free( line );
+ if ( ferror( fIDX ) ) {
+ perror( IDX );
+ fclose( fIDX );
+ exit( errno );
+ }
+ fclose( fIDX );
+
+ CloseAllIDX();
+
+ CallMakeIndex();
+}
+
+int main( int argc, char * const argv[] ) {
+ int retVal = 0;
+
+ ScanArguments( argc, argv );
+
+ if ( Verbose > 0 ) {
+ show_version();
+ if ( Verbose > 9 ) {
+ int i;
+ printf( "Identify: \"%s\"\n", Identify );
+ printf( "ResultIs: \"%s\"\n", ResultIs );
+ printf( "SuffixIs: \"%s\"\n", SuffixIs );
+ printf( "IDX: \"%s\"\n", IDX );
+ printf( "Jobname: \"%s\"\n", Jobname );
+ printf( "MakeIndex: \"%s\"", MakeIndex );
+ for ( i = 0; i < MakeIndexArgc; i++ )
+ printf( " \"%s\"", MakeIndexArgs[i] );
+ printf( "\n" );
+ }
+ }
+
+ ProcessIDXFile();
+
+ return retVal;
+}