/* * csv2latex.c, copyright © 2003 Benoît Rouits * ********************************************************* * csv2latex translates a .csv file to a LaTex document. * ********************************************************* * 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * see the COPYING file included in the csv2latex package or * http://www.gnu.org/licenses/gpl.txt for the full licence * */ #include #include #include #include #include #include #include #define PACKAGE "csv2latex" #define RELEASE_DATE "2006/03/04" #define VERSION "0.9" typedef struct { char* tab; int size; } texcape; typedef struct { char pos; char block; char sep; int rows; int lines; int guess; int header; texcape* tex; } config; void rtfm(char* prog) { printf("Usage: %s --nohead --guess | " "--separator [(c)omma|(s)emicolon|(t)ab] " "--block [(q)uote|(d)ouble|(n)one] " "--lines n " "--position [l|c|r] " " csv_file.csv\n", basename(prog)); printf("%s translates a csv file to a LaTeX file\n", basename(prog)); return; } config* parseOptions (config* conf, int argc, char **argv) { /* Thanks to */ int opt; #if defined USE_GETOPT #else int longopt_index = 0; static struct option long_options[] = { {"help", 0, NULL, 'h'}, {"guess", 0, NULL, 'g'}, {"block", 1, NULL, 'b'}, {"lines", 1, NULL, 'l'}, {"nohead", 0, NULL, 'n'}, {"version", 0, NULL, 'v'}, {"position", 1, NULL, 'p'}, {"separator", 1, NULL, 's'}, {NULL, 0, NULL, 0} /* marks end-of-list */ }; #endif #if defined USE_GETOPT while ((opt = getopt (argc, argv, "hvg?b:l:p:s:")) != EOF) { #else while ((opt = getopt_long (argc, argv, "hvg?b:l:p:s:", long_options, &longopt_index)) > 0) { #endif switch (opt) { case '?': case 'h': rtfm (argv[0]); exit (EXIT_SUCCESS); case 'g': /* guess the CSV */ conf->guess=1; break; case 'b': /* csv block delimiter */ if(optarg[0] == 'q') conf->block = '\''; else if(optarg[0] == 'd') conf->block = '"'; else if(optarg[0] == 'n') conf->block = 0; /* no block delimiter */ break; case 'l': /* number of lines per TeX tabulars */ if(isdigit(optarg[0])) conf->lines=atoi(optarg); else{ rtfm(argv[0]); exit(EXIT_SUCCESS); } break; case 'n': conf->header=0; break; case 'v': /* version */ printf ("Version %s, %s\n" "%s (c) 2003 Benoît Rouits \n\n", VERSION, RELEASE_DATE, PACKAGE); exit (EXIT_SUCCESS); case 'p': /* LaTeX position in cell */ conf->pos=optarg[0]; /* position char in cell */ break; case 's': /* csv block separator */ if(optarg[0] == 'c') conf->sep = ','; else if(optarg[0] == 's') conf->sep = ';'; else if(optarg[0] == 't') conf->sep = '\t'; break; } } return conf; } int guessCSV(config* conf, FILE* in) { /* guess the block delimiter and the csv separator */ int token; token=getc(in); /* first char is block separator */ if(token == EOF){ return(-1); }else if (ispunct(token)){ /* found first block delimiter */ conf->block=token; fprintf(stderr,"Guessed %c as Block Delimiter\n", conf->block); while((token=getc(in)) != conf->block && token != '\n' && token != EOF){ }/* just getc */ if(token == conf->block){ /* second delimiter : next is separator */ conf->sep=getc(in); fprintf(stderr,"Guessed %c as Separator\n", conf->sep); return(0); }else{ return (-1); /* what else ? */ } }else{ /* no block delimiter */ conf->block=0; fprintf(stderr,"Guessed No Block Delimiter\n"); while(isalnum((token=getc(in))) && token != '\n' && token != EOF){ }/* just getc */ if(ispunct(token) || token == '\t' || token == ' '){ /* several possible separators */ conf->sep=token; fprintf(stderr,"Guessed %c as Separator\n", conf->sep); return(0); }else{ return(-1); /* what else ? */ } } return(0); } int getMaxrows(char sep, FILE* in) { /* gets the number of rows of a csv file assuming a separator */ int token='\0'; int cur=0; int max=0; while(token != EOF){ while(token != sep && token != '\n' && token != EOF){ token=getc(in); } if(token == sep){ cur++; token=getc(in); } if(token == '\n'){ cur++; max=(maxrows; lines=conf->lines; while(token!=EOF){ token=getc(in); while(token != conf->sep && token != '\n' && token != EOF){ if(token != conf->block){ /* remove csv block quote */ int i=0; for(i=0;i < conf->tex->size; i++){/* look TeX char to escape */ if(token == conf->tex->tab[i]){ fprintf(out, "\\%c", token); break; } } if(i >= conf->tex->size) /* print char if no break */ putc(token, out); } token=getc(in); } if(token == conf->sep){ putc(newsep,out); numrows--; } if(token == '\n'){ while(numrows>1){ putc(newsep,out); numrows--; } fprintf(out,"\\\\\n"); /* TeX new line */ fprintf(out,"\\hline\n"); /* TeX draw hline */ numrows=max; lines--; if(!lines){ fprintf(out,"\\end{tabular}\n"); fprintf(out,"\\begin{tabular}{|"); while(numrows--) fprintf(out, "%c|", conf->pos); fprintf(out, "}\n"); fprintf(out, "\\hline\n"); numrows=max; lines=conf->lines; } } } return; } void doTeXdoc(config* conf, FILE* in, FILE* out) { /* prepares the LaTeX layout */ int maxrows; int numrows; numrows=maxrows=conf->rows; if(conf->header){ fprintf(out, "\\documentclass[a4paper]{article}\n"); fprintf(out, "\\usepackage[T1]{fontenc}\n"); fprintf(out, "\\usepackage[latin1]{inputenc}\n"); fprintf(out, "\\begin{document}\n"); } fprintf(out, "\\begin{tabular}{|"); while(numrows--) fprintf(out, "%c|",conf->pos); /* position in cell */ fprintf(out, "}\n"); fprintf(out, "\\hline\n"); doTeXsub(conf, '&', in, out); /* & is LaTeX sep */ fprintf(out, "\\end{tabular}\n"); if(conf->header){ fprintf(out, "\\end{document}\n"); } return; } int main (int argc, char **argv) { FILE* fp; config* conf; extern int optind, opterr, optopt; if(argc == 1){ rtfm(argv[0]); exit(EXIT_SUCCESS); } conf=(config*)malloc(sizeof(config)); /* defaults : */ conf->rows=4; conf->pos='l'; conf->lines=40; conf->guess=0; conf->sep=','; conf->block='"'; conf->header=1; /* TeX charaters to escape */ conf->tex=(texcape*)malloc(sizeof(texcape)); conf->tex->tab = "_#$%^&{}~"; conf->tex->size = 9; conf=parseOptions(conf, argc, argv); fp=fopen(argv[optind],"r"); if(conf->guess){ if(guessCSV(conf, fp)){ fprintf(stderr,"Can't guess CSV separators\n"); exit(EXIT_FAILURE); } rewind(fp); } conf->rows=getMaxrows(conf->sep, fp); rewind(fp); doTeXdoc(conf, fp, stdout); free(conf->tex); free(conf); fclose(fp); return 0; }