From: Sebastian Harl Date: Sun, 13 Jun 2010 20:42:14 +0000 (+0200) Subject: Initial commit. X-Git-Url: https://git.tokkee.org/?p=lm2latex.git;a=commitdiff_plain;h=1ee7560753cd0e1c3b3f0ff1f27fbe539a37e726 Initial commit. So far, the tool is able to parse most (all but tables) of the Linux-Magazin markup language and output an appropriate LaTeX file. --- 1ee7560753cd0e1c3b3f0ff1f27fbe539a37e726 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84dd827 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# build system stuff +.deps +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +compile +config.* +configure +depcomp +install-sh +missing +stamp-h1 +version +ylwrap + +# ltdl stuff +libtool +ltmain.sh + +# build output +.libs +*.la +*.lo +*.o +l2l_features.h +l2l_scanner.[ch] +lm2latex + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..1228c7b --- /dev/null +++ b/COPYING @@ -0,0 +1,24 @@ +Copyright (c) 2010 Sebastian Harl +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..23e5f25 --- /dev/null +++ b/INSTALL @@ -0,0 +1,236 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). Here is a another example: + + /bin/bash ./configure CONFIG_SHELL=/bin/bash + +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..688649f --- /dev/null +++ b/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = src + +EXTRA_DIST = autogen.sh version-gen.sh + diff --git a/README b/README new file mode 100644 index 0000000..8e3a6c3 --- /dev/null +++ b/README @@ -0,0 +1,39 @@ +lm2latex +======== + + lm2latex (Linux-Magazin to LaTeX) converts a text file formatted using the + "Linux Magazin" markup to a LaTeX file. + + This is free and open source software, licensed under the 2-clause BSD + license. See COPYING for details. + +Prerequisites +------------- + + To compile the lm2latex package from source you need: + + * A build environment: autotools, libtool, C compiler, ... + + * A POSIX + Single UNIX Specification compatible C library. + + * The lexical analyzer generator "flex". + +Configuring / Compiling / Installing +------------------------------------ + + To configure, build and install lm2latex with the default settings, run + `./configure && make && make install'. For detailed, generic instructions + see INSTALL. For a complete list of configure options and their description, + run `./configure --help'. + + By default, lm2latex will be installed into `/opt/lm2latex'. You can adjust + this setting by specifying the `--prefix' configure option - see INSTALL for + details. If you pass DESTDIR= to `make install', will be + prefixed to all installation directories. This might be useful when creating + packages for lm2latex. + +Author +------ + + Sebastian "tokkee" Harl + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..7c7c72f --- /dev/null +++ b/autogen.sh @@ -0,0 +1,17 @@ +#! /bin/sh + +libtoolize=libtoolize + +if which glibtoolize > /dev/null 2>&1; then + libtoolize=glibtoolize +fi + +set -ex + +aclocal --force --warnings=all +$libtoolize --automake --copy --force +aclocal +autoconf --force --warnings=all +autoheader --force --warnings=all +automake --add-missing --copy --foreign --warnings=all + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..31d2f03 --- /dev/null +++ b/configure.ac @@ -0,0 +1,197 @@ +dnl Process this file with autoconf to produce a configure script. +dnl +dnl This is the lm2latex configure script. +dnl +dnl Copyright (C) 2010 Sebastian Harl +dnl All rights reserved. +dnl +dnl Redistribution and use in source and binary forms, with or without +dnl modification, are permitted provided that the following conditions +dnl are met: +dnl 1. Redistributions of source code must retain the above copyright +dnl notice, this list of conditions and the following disclaimer. +dnl 2. Redistributions in binary form must reproduce the above copyright +dnl notice, this list of conditions and the following disclaimer in the +dnl documentation and/or other materials provided with the distribution. +dnl +dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +dnl ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +dnl TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +dnl PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR +dnl CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +dnl EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +dnl PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +dnl OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +dnl WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +dnl OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +dnl ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +AC_INIT([lm2latex],[m4_esyscmd(./version-gen.sh)], + [Sebastian Harl ], [], + [http://git.tokkee.org/?p=lm2latex.git]) +AC_CONFIG_SRCDIR([src/lm2latex.c]) +AC_CONFIG_HEADERS([src/config.h]) +AC_PREFIX_DEFAULT([/opt/lm2latex]) + +AM_INIT_AUTOMAKE([foreign -Wall]) + +AC_LANG(C) + +AC_SYS_LARGEFILE + +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET + +AM_PROG_CC_C_O +AM_PROG_LEX + +m4_ifdef([LT_INIT], + [ + LT_INIT + ], + # else + # (older libtools) + [ + AC_PROG_LIBTOOL + ] +) + +test_cc_flags() { + AC_LANG_CONFTEST([int main() {}]) + $CC -c conftest.c $CFLAGS $@ > /dev/null 2> /dev/null + ret=$? + rm -f conftest.o + return $ret +} + +m4_divert_once([HELP_ENABLE], [ +Build options:]) + +dnl Optionally stick to standard C99 and POSIX:2001 as close as possible. +AC_ARG_ENABLE([standards], + AS_HELP_STRING([--enable-standards], + [C99 / POSIX standards compliance mode @<:@default=no@:>@]), + [enable_standards="$enableval"], + [enable_standards="no"]) + +if test "x$enable_standards" = "xyes"; then + AC_DEFINE([_ISOC99_SOURCE], 1, + [Define to enforce ISO/IEC 9899:1999 (C99) compliance.]) + AC_DEFINE([_POSIX_C_SOURCE], 200112L, + [Define to enforce IEEE 1003.1-2001 (POSIX:2001) compliance.]) + AC_DEFINE([_XOPEN_SOURCE], 600, + [Define to enforce X/Open 6 (XSI) compliance.]) + AC_DEFINE([_REENTRANT], 1, + [Define to enable reentrant interfaces.]) + AC_DEFINE([_THREAD_SAFE], 1, + [Define to enable reentrant interfaces.]) + + for flag in -std=c99 -pedantic; do + AC_MSG_CHECKING([whether $CC accepts $flag]) + + if test_cc_flags $flag; then + CFLAGS="$CFLAGS $flag" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + done +fi + +dnl Hardening (see e.g. http://wiki.debian.org/Hardening for a motivation). +AC_DEFINE([_FORTIFY_SOURCE], 2, + [Define to enable protection against static sized buffer overflows.]) +AC_ARG_ENABLE([hardening], + AS_HELP_STRING([--disable-hardening], + [hardening options @<:@default=yes@:>@]), + [enable_hardening="$enableval"], + [enable_hardening="yes"]) + +if test "x$enable_hardening" = "xyes"; then + hardening=0 + hardening_tests=0 + for flag in -Wformat -Wformat-security; do + hardening_tests=$(($hardening_tests + 1)) + AC_MSG_CHECKING([whether $CC accepts $flag]) + + if test_cc_flags $flag; then + CFLAGS="$CFLAGS $flag" + hardening=$(($hardening + 1)) + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + done + if test $hardening -ne $hardening_tests; then + AC_MSG_WARN( + [Some hardening options are not supported by your compiler!]) + fi +fi + +dnl Strict checking for potential problems. +AC_ARG_ENABLE([strict-checks], + AS_HELP_STRING([--disable-strict-checks], + [strict compiler checks @<:@default=yes@:>@]), + [enable_strict_checks="$enableval"], + [enable_strict_checks="yes"]) + +STRICT_CFLAGS="" +for flag in -Wall -Werror; do + AC_MSG_CHECKING([whether $CC accepts $flag]) + + if test_cc_flags $flag; then + STRICT_CFLAGS="$STRICT_CFLAGS $flag" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi +done + +if test "x$enable_strict_checks" = "xyes"; then + for flag in -Wextra \ + -Wbad-function-cast \ + -Wcast-align \ + -Wcast-qual \ + -Wconversion \ + -Wdeclaration-after-statement \ + -Wmissing-prototypes \ + -Wpointer-arith \ + -Wshadow \ + -Wstrict-prototypes \ + -Wunreachable-code; do + AC_MSG_CHECKING([whether $CC accepts $flag]) + + if test_cc_flags $flag; then + STRICT_CFLAGS="$STRICT_CFLAGS $flag" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + done +fi +AC_SUBST([STRICT_CFLAGS]) + +AC_CHECK_HEADERS(libgen.h) + +AC_CONFIG_FILES([Makefile src/Makefile]) +AC_OUTPUT + +cat < l2l_features.h + +.PHONY: FORCE + diff --git a/src/l2l.c b/src/l2l.c new file mode 100644 index 0000000..2fae2b9 --- /dev/null +++ b/src/l2l.c @@ -0,0 +1,161 @@ +/* + * lm2latex - src/l2l.c + * Copyright (C) 2010 Sebastian Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * A Linux-Magazin markup to LaTeX converter -- core library. + */ + +#include "l2l.h" +#include "l2l_scanner.h" +#include "l2l_features.h" + +#include + +#include + +/* + * private helper functions + */ + +static void +write_tex_preamble(FILE *out) +{ + assert(out); + + fprintf(out, +"\\documentclass[11pt,a4paper,twoside]{article}\n" +"\n" +"\\usepackage{ifpdf}\n" +"\n" +"\\usepackage{a4}\n" +"\\usepackage{fancyhdr}\n" +"\\ifpdf\n" +"\\usepackage[pdftex]{graphicx}\n" +"\\else\n" +"\\usepackage[dvips]{graphicx}\n" +"\\fi\n" +"\n" +"\\usepackage{listings}\n" +"\\lstset{breaklines=true,breakatwhitespace=true}\n" +"\\lstset{prebreak=\\mbox{$\\hookleftarrow$}}\n" +"\\lstset{basicstyle=\\footnotesize\\ttfamily}\n" +"\n" +"\\usepackage[ngerman]{babel}\n" +"\\usepackage[latin1]{inputenc}\n" +"\\usepackage[T1]{fontenc}\n" +"\\usepackage{lmodern}\n" +"\n" +"\\ifpdf\n" +"\\usepackage[a4paper,margin=15mm,top=25mm,bottom=20mm,pdftex]{geometry}\n" +"\\else\n" +"\\usepackage[a4paper,margin=15mm,top=25mm,bottom=20mm,dvips]{geometry}\n" +"\\fi\n" +"\n" +"\\usepackage{caption}\n" +"\\usepackage{url}\n" +"\n" +"\\setlength{\\parskip}{6pt}\n" +"\n" +"\\renewcommand{\\headrulewidth}{0.4pt}\n" +"\\renewcommand{\\footrulewidth}{0pt}\n" +"\n" +"\\fancypagestyle{headings}\n" +"\\fancyhead{}\n" +"\\fancyhead[LO,RE]{}\n" +"\\fancyhead[LE,RO]{\\thepage}\n" +"\\fancyfoot{}\n" +"\n" +"\\pagestyle{fancy}\n" +"\n"); +} /* write_tex_preamble */ + +/* + * public API + */ + +int +l2l_convert_file_fh(FILE *in, FILE *out) +{ + yyscan_t scanner; + + int status; + + write_tex_preamble(out); + + l2l_yylex_init(&scanner); + l2l_yyset_in(in, scanner); + l2l_yyset_out(out, scanner); + + status = l2l_yylex(scanner); + + l2l_yylex_destroy(scanner); + return status; +} /* l2l_convert_file_fh */ + +int +l2l_convert_file(const char *infile, const char *outfile) +{ + FILE *in, *out; + + int status; + + in = fopen(infile, "r"); + if (! in) + return -1; + + out = fopen(outfile, "w"); + if (! out) { + fclose(in); + return -1; + } + + status = l2l_convert_file_fh(in, out); + fclose(in); + fclose(out); + return status; +} /* l2l_convert_file */ + +unsigned int +l2l_version(void) +{ + return L2L_VERSION; +} /* l2l_version */ + +const char * +l2l_version_string(void) +{ + return L2L_VERSION_STRING; +} /* l2l_version_string */ + +const char * +l2l_version_extra(void) +{ + return L2L_VERSION_EXTRA; +} /* l2l_version_extra */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/l2l.h b/src/l2l.h new file mode 100644 index 0000000..b4a9014 --- /dev/null +++ b/src/l2l.h @@ -0,0 +1,54 @@ +/* + * lm2latex - src/l2l.h + * Copyright (C) 2010 Sebastian Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * A Linux-Magazin markup to LaTeX converter -- core library. + */ + +#ifndef L2L_H +#define L2L_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int +l2l_convert_file_fh(FILE *in, FILE *out); + +int +l2l_convert_file(const char *infile, const char *outfile); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! L2L_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/l2l_features.h.in b/src/l2l_features.h.in new file mode 100644 index 0000000..47b3575 --- /dev/null +++ b/src/l2l_features.h.in @@ -0,0 +1,69 @@ +/* + * lm2latex - src/l2l_features.h + * Copyright (C) 2010 Sebastian Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Feature description of lm2latex. + */ + +#ifndef L2L_FEATURES_H +#define L2L_FEATURES_H 1 + +#define L2L_VERSION_MAJOR @L2L_VERSION_MAJOR@ +#define L2L_VERSION_MINOR @L2L_VERSION_MINOR@ +#define L2L_VERSION_PATCH @L2L_VERSION_PATCH@ + +#define L2L_VERSION_EXTRA "@L2L_VERSION_EXTRA@" + +#define L2L_VERSION_STRING "@L2L_VERSION_STRING@" + +#define L2L_VERSION_ENCODE(major, minor, patch) \ + ((major) * 10000 + (minor) * 100 + (patch)) + +#define L2L_VERSION L2L_VERSION_ENCODE(L2L_VERSION_MAJOR, \ + L2L_VERSION_MINOR, L2L_VERSION_PATCH) + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned int +l2l_version(void); + +const char * +l2l_version_string(void); + +const char * +l2l_version_extra(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! L2L_FEATURES_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/l2l_scanner.l b/src/l2l_scanner.l new file mode 100644 index 0000000..d769e91 --- /dev/null +++ b/src/l2l_scanner.l @@ -0,0 +1,675 @@ +/* + * lm2latex - src/l2l_scanner.l + * Copyright (C) 2010 Sebastian Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * A Linux-Magazin markup to LaTeX converter -- LM markup scanner. + */ + +%{ +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#include +#include +#include +#include + +typedef struct { + char *data; + size_t size; + size_t len; +} l2l_strbuf_t; + +#define L2L_STRBUF_INIT { NULL, 0, 0 } +#define L2L_STRBUF_FREE(buf) ((buf)->size - (buf)->len) +#define L2L_STRBUF_END(buf) ((buf)->data + (buf)->len) +#define L2L_STRBUF_CLEAR(buf) ((buf)->len = 0) + +static int +l2l_strbuf_append(l2l_strbuf_t *buf, const char *fmt, ...); + +static void +l2l_strbuf_chomp(l2l_strbuf_t *buf); + +static void +l2l_strbuf_destroy(l2l_strbuf_t *buf); + +#define L2L_YY_APPEND_OR_ECHO(strbuf, ...) \ + do { \ + if ((strbuf)) { \ + if (l2l_strbuf_append((strbuf), __VA_ARGS__)) \ + YY_FATAL_ERROR("ERROR: internal error"); \ + } \ + else \ + fprintf(yyout, __VA_ARGS__); \ + } while (0) + +#define L2L_STATE_HEADER_OR_ABORT \ + do { \ + if (l2l_scanner_state != L2L_HEADER) \ + YY_FATAL_ERROR("ERROR: unexpected header definition"); \ + } while (0) + +#define L2L_PATTERN_IS(str) (! strncmp(yytext, (str), strlen(str))) +#define L2L_PATTERN_IS_HEADER \ + (L2L_PATTERN_IS("@R:") || L2L_PATTERN_IS("@SW:") \ + || L2L_PATTERN_IS("@D:") || L2L_PATTERN_IS("@T:") \ + || L2L_PATTERN_IS("@A:") || L2L_PATTERN_IS("@V:")) +%} + +%option yylineno +%option noyywrap + +/* optimize for "fast scanning"; create an 8-bit scanner */ +%option fast 8bit + +/* generate a reentrant scanner in its own namespace */ +%option reentrant +%option prefix="l2l_yy" outfile="lex.yy.c" + +%option verbose warn + +%s box + +%x caption box_caption +%x command +%x headertxt +%x itemize +%x listing +%x title +%x url + +COMMENT @#:.* +WHITESPACE [ \t] + +ANY_COMMAND @(R|SW|D|T|V|A|L|ZT|LI|B|Bi|IT|IL|IE|KT|KL|KE|TT|TH|TL|TE): + +%% + +%{ + enum { + L2L_HEADER, + L2L_BODY, + L2L_FIGURE, + + L2L_UNQUOTED_TEXT, + L2L_QUOTED_TEXT, + }; + + int l2l_scanner_state = L2L_HEADER; + int l2l_quote_state = L2L_UNQUOTED_TEXT; + + /* text formatting */ + _Bool l2l_italic = 0; + _Bool l2l_bold = 0; + _Bool l2l_code = 0; + _Bool l2l_sup = 0; + _Bool l2l_sub = 0; + _Bool l2l_li_italic = 0; + + /* title page information */ + l2l_strbuf_t l2l_category = L2L_STRBUF_INIT; + l2l_strbuf_t l2l_keyword = L2L_STRBUF_INIT; + l2l_strbuf_t l2l_title = L2L_STRBUF_INIT; + l2l_strbuf_t l2l_headline = L2L_STRBUF_INIT; + l2l_strbuf_t l2l_author = L2L_STRBUF_INIT; + l2l_strbuf_t l2l_abstract = L2L_STRBUF_INIT; + + /* temp. buffers */ + l2l_strbuf_t l2l_caption = L2L_STRBUF_INIT; + l2l_strbuf_t l2l_ititle = L2L_STRBUF_INIT; + + l2l_strbuf_t *l2l_buf_ptr = NULL; + + int l2l_last_yystart = INITIAL; +%} + +{COMMENT} { fprintf(yyout, "%%%s", yytext + strlen("@#:")); } + +{ + /* LaTeX reserved characters */ + [#$%&_{}] { L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "\\%s", yytext); } + [\^~] { L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "\\%s{}", yytext); } + [\\] { L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "$\\backslash$"); } + + /* special characters */ + /* '---' and '--' are handled by LaTeX */ + \*\* L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "~"); + + :\* L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "\\,"); + + ["] { + if (l2l_quote_state == L2L_UNQUOTED_TEXT) { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "\"`"); + l2l_quote_state = L2L_QUOTED_TEXT; + } + else { + assert(l2l_quote_state == L2L_QUOTED_TEXT); + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "\"'"); + l2l_quote_state = L2L_UNQUOTED_TEXT; + } + } + + /* text formatting */ + \<[iI]> { + if (l2l_italic) { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "}"); + l2l_italic = 0; + } + else { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "{\\itshape "); + l2l_italic = 1; + } + } + + \<[bB]> { + if (l2l_bold) { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "}"); + l2l_bold = 0; + } + else { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "{\\bfseries "); + l2l_bold = 1; + } + } + + \<[cC]> { + if (l2l_code) { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "}"); + l2l_code = 0; + } + else { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "{\\ttfamily "); + l2l_code = 1; + } + } + + \<[\+]> { + if (l2l_sup) { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "}}"); + l2l_sup = 0; + } + else { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, + "\\ensuremath{^{\rmfamily "); + l2l_sup = 1; + } + } + + \<[\-]> { + if (l2l_sub) { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "}}"); + l2l_sub = 0; + } + else { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, + "\\ensuremath{_{\rmfamily "); + l2l_sub = 1; + } + } +} + +\<[uU]> { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "\\url{"); + BEGIN(url); +} + +\<[uU]> { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "}"); + BEGIN(l2l_last_yystart); +} + +.|\n { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "%s", yytext); +} + + /* + * header + */ + +@R:{WHITESPACE}* { + L2L_STATE_HEADER_OR_ABORT; + l2l_buf_ptr = &l2l_category; + BEGIN(headertxt); +} + +@SW:{WHITESPACE}* { + L2L_STATE_HEADER_OR_ABORT; + l2l_buf_ptr = &l2l_keyword; + BEGIN(headertxt); +} + +@D:{WHITESPACE}* { + L2L_STATE_HEADER_OR_ABORT; + l2l_buf_ptr = &l2l_title; + BEGIN(headertxt); +} + +@T:{WHITESPACE}* { + L2L_STATE_HEADER_OR_ABORT; + l2l_buf_ptr = &l2l_headline; + BEGIN(headertxt); +} + +@A:{WHITESPACE}* { + L2L_STATE_HEADER_OR_ABORT; + l2l_buf_ptr = &l2l_author; + BEGIN(headertxt); +} + +@V:{WHITESPACE}* { + L2L_STATE_HEADER_OR_ABORT; + l2l_buf_ptr = &l2l_abstract; + BEGIN(headertxt); +} + +{ANY_COMMAND} { + if (l2l_buf_ptr) { + l2l_strbuf_chomp(l2l_buf_ptr); + l2l_buf_ptr = NULL; + } + + if (! L2L_PATTERN_IS_HEADER) { + assert(l2l_scanner_state == L2L_HEADER); + + if (l2l_category.len || l2l_keyword.len + || l2l_title.len || l2l_headline.len) { + fprintf(yyout, "\\title{"); + + if (l2l_category.len || l2l_keyword.len) { + fprintf(yyout, "{\\scriptsize ["); + if (l2l_category.len) { + fprintf(yyout, "%s", l2l_category.data); + if (l2l_keyword.len) + fprintf(yyout, " $\\rightarrow$ "); + } + if (l2l_keyword.len) + fprintf(yyout, "%s", l2l_keyword.data); + fprintf(yyout, "]}\\\\\n\\vspace{5mm}\n"); + } + + if (l2l_headline.len) { + if (l2l_title.len) + fprintf(yyout, "\\normalsize %s\\\\\n\\LARGE ", + l2l_title.data); + fprintf(yyout, "%s", l2l_headline.data); + } + else if (l2l_title.len) + fprintf(yyout, "%s", l2l_title.data); + + fprintf(yyout, "}\n"); + } + + if (l2l_author.len) + fprintf(yyout, "\\author{%s}\n", l2l_author.data); + fprintf(yyout, "\\date{\\today}\n\n"); + + fprintf(yyout, "\\begin{document}\n\n"); + l2l_scanner_state = L2L_BODY; + + fprintf(yyout, "\\maketitle\n\n"); + + if (l2l_abstract.len) + fprintf(yyout, "\\begin{abstract}\n%s\n" + "\\end{abstract}\n\n", l2l_abstract.data); + + fprintf(yyout, "\\twocolumn\n\n"); + } + + yyless(0); + BEGIN(l2l_last_yystart); +} + +{COMMENT} { /* ignore */ } + +.|\n { + if (l2l_buf_ptr) + if (l2l_strbuf_append(l2l_buf_ptr, "%s", yytext)) + YY_FATAL_ERROR("ERROR: internal error"); + /* else ignore */ +} + + /* + * body + */ + +\n\n{WHITESPACE}*\*{WHITESPACE}* { + fprintf(yyout, "\n\n\\begin{itemize}\n\\item "); + BEGIN(itemize); +} + +({WHITESPACE}|\n)*\n\n | +({WHITESPACE}|\n)*{ANY_COMMAND} { + fprintf(yyout, "\n\\end{itemize}"); + yyless(0); + BEGIN(l2l_last_yystart); +} + + /* this will produce a longer match and, thus, take precedence over + * the pattern above matching an empty line after the itemize */ +({WHITESPACE}|\n)*\n{WHITESPACE}*\*{WHITESPACE}* { + fprintf(yyout, "\n\\item "); +} +({WHITESPACE}|\n)*\n\n({WHITESPACE}{2,}|\t) ECHO; + +. ECHO; + +@ZT:{WHITESPACE}* { + fprintf(yyout, "\\subsection*{"); + BEGIN(command); +} + +({WHITESPACE}|\n)+{ANY_COMMAND} { + fprintf(yyout, "}"); + yyless(0); + BEGIN(l2l_last_yystart); +} + +. ECHO; + +@LI:{WHITESPACE}*\n? { + /* \xb7 = MIDDLE DOT (iso-8859-1 and iso-8859-15) */ + fprintf(yyout, "\\begin{lstlisting}[escapechar=\xb7]\n"); + BEGIN(listing); +} + +\n*{ANY_COMMAND} { + fprintf(yyout, "\n\\end{lstlisting}"); + yyless(0); + BEGIN(l2l_last_yystart); +} + +\<§§I> { + if (l2l_li_italic) { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "\xb7"); + l2l_li_italic = 0; + } + else { + L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "\xb7\\itshape "); + l2l_li_italic = 1; + } +} + +§§\n /* ignore => lstlisting will insert appropriate arrows */; + +. ECHO; + + /* + * images/boxes + */ + +@(B|KT):{WHITESPACE}* { + if (l2l_scanner_state != L2L_FIGURE) { + fprintf(yyout, "\\begin{figure}\n"); + l2l_scanner_state = L2L_FIGURE; + } + else { + l2l_scanner_state = L2L_BODY; + } + + l2l_buf_ptr = &l2l_caption; + if (! strncmp(yytext, "@B:", 3)) + BEGIN(caption); + else if (! strncmp(yytext, "@KT:", 4)) + BEGIN(box_caption); + else + assert(0); +} + +@Bi:.*\n { + char *filename; + + yytext[yyleng - 1] = '\0'; + + filename = yytext + strlen("@Bi:"); + while (isspace((int)*filename)) + ++filename; + + if (l2l_scanner_state != L2L_FIGURE) { + fprintf(yyout, "\\begin{figure}\n"); + l2l_scanner_state = L2L_FIGURE; + } + else { + l2l_scanner_state = L2L_BODY; + } + + fprintf(yyout, "\\includegraphics[width=\\columnwidth]{%s}\n", filename); + + if (l2l_scanner_state == L2L_BODY) + fprintf(yyout, "\\end{figure}\n"); +} + +@KL: { + if (l2l_scanner_state != L2L_FIGURE) { + fprintf(yyout, "\\begin{figure}\n"); + l2l_scanner_state = L2L_FIGURE; + } + else { + l2l_scanner_state = L2L_BODY; + } + + l2l_last_yystart = box; + BEGIN(box); +} + +@(KE|L):{WHITESPACE}* { + fprintf(yyout, "\\end{figure}"); + l2l_scanner_state = L2L_BODY; + l2l_last_yystart = INITIAL; + BEGIN(l2l_last_yystart); +} + +{ANY_COMMAND} { + if (l2l_buf_ptr) { + l2l_strbuf_chomp(l2l_buf_ptr); + l2l_buf_ptr = NULL; + } + + if (l2l_caption.len) { + fprintf(yyout, "\\caption*{%s}\n", l2l_caption.data); + L2L_STRBUF_CLEAR(&l2l_caption); + } + + if ((l2l_scanner_state == L2L_BODY) && (YY_START != box_caption)) + fprintf(yyout, "\\end{figure}\n\n"); + + yyless(0); + if (YY_START == caption) + BEGIN(l2l_last_yystart); + else if (YY_START == box_caption) { + l2l_last_yystart = box; + BEGIN(box); + } + else + assert(0); +} + +{COMMENT} { /* ignore */ } + +.|\n { + if (l2l_buf_ptr) + if (l2l_strbuf_append(l2l_buf_ptr, "%s", yytext)) + YY_FATAL_ERROR("ERROR: internal error"); + /* else ignore */ +} + + /* + * infos + */ + +@IT:{WHITESPACE}* { + l2l_buf_ptr = &l2l_ititle; + BEGIN(title); +} + +{ANY_COMMAND} { + if (l2l_buf_ptr) { + l2l_strbuf_chomp(l2l_buf_ptr); + l2l_buf_ptr = NULL; + } + + if (l2l_ititle.len) { + fprintf(yyout, "\\subsection*{\\rule{\\columnwidth}{1pt}" + "\\newline %s}\n", l2l_ititle.data); + L2L_STRBUF_CLEAR(&l2l_ititle); + } + + yyless(0); + BEGIN(l2l_last_yystart); +} + +<title>{COMMENT} { /* ignore */ } + +<title>.|\n { + if (l2l_buf_ptr) + if (l2l_strbuf_append(l2l_buf_ptr, "%s", yytext)) + YY_FATAL_ERROR("ERROR: internal error"); + /* else ignore */ +} + +@IL: { /* ignore */ } + +@IE: { /* ignore */ } + + /* + * tables + */ + +@TT: /* TODO */; + +@TH: /* TODO */; + +@TL: /* TODO */; + +@TE: /* TODO */; + + /* let all other rules that match "@L:" have a higher preceedence */ +@L:{WHITESPACE}* { /* nothing to do */ } + +<<EOF>> { + if (l2l_scanner_state == L2L_BODY) { + fprintf(yyout, "\\end{document}\n"); + } + else + YY_FATAL_ERROR("ERROR: incomplete document"); + + l2l_strbuf_destroy(&l2l_category); + l2l_strbuf_destroy(&l2l_keyword); + l2l_strbuf_destroy(&l2l_title); + l2l_strbuf_destroy(&l2l_headline); + l2l_strbuf_destroy(&l2l_author); + l2l_strbuf_destroy(&l2l_abstract); + + l2l_strbuf_destroy(&l2l_caption); + l2l_strbuf_destroy(&l2l_title); + + yyterminate(); +} + +%% + +static int +l2l_strbuf_append(l2l_strbuf_t *buf, const char *fmt, ...) +{ + size_t str_len; + va_list ap; + + int status; + + if ((! buf) || (! fmt)) + return 0; + + va_start(ap, fmt); + status = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + + if (status <= 0) + return -1; + + str_len = (size_t)status; + + if (str_len > L2L_STRBUF_FREE(buf)) { + char *new_data; + size_t new_size = 2 * buf->size; + + if (str_len > buf->size) + new_size += str_len; + + new_data = realloc(buf->data, new_size + 1); + if (! new_data) { + l2l_strbuf_destroy(buf); + return -1; + } + + buf->data = new_data; + buf->size = new_size; + } + assert(buf->len + str_len <= buf->size); + + va_start(ap, fmt); + status = vsnprintf(L2L_STRBUF_END(buf), L2L_STRBUF_FREE(buf) + 1, fmt, ap); + va_end(ap); + + if (status <= 0) + return -1; + + assert((size_t)status == str_len); + buf->len += str_len; + buf->data[buf->len] = '\0'; + return 0; +} /* l2l_strbuf_append */ + +static void +l2l_strbuf_chomp(l2l_strbuf_t *buf) +{ + if (! buf) + return; + + while (buf->len && isspace((int)buf->data[buf->len - 1])) { + buf->data[buf->len - 1] = '\0'; + --buf->len; + } +} /* l2l_strbuf_chomp */ + +static void +l2l_strbuf_destroy(l2l_strbuf_t *buf) +{ + if (! buf) + return; + + if (buf->data) + free(buf->data); + memset(buf, 0, sizeof(*buf)); +} /* l2l_strbuf_destroy */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/lm2latex.c b/src/lm2latex.c new file mode 100644 index 0000000..297dab7 --- /dev/null +++ b/src/lm2latex.c @@ -0,0 +1,151 @@ +/* + * lm2latex - src/lm2latex.c + * Copyright (C) 2010 Sebastian Harl <sh@tokkee.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * A Linux-Magazin markup to LaTeX converter. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "l2l.h" +#include "l2l_features.h" + +#include <errno.h> + +#if HAVE_LIBGEN_H +# include <libgen.h> +#else /* HAVE_LIBGEN_H */ +# define basename(path) (path) +#endif /* ! HAVE_LIBGEN_H */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <unistd.h> + +static void +exit_usage(char *name, int status) +{ + printf( +"Usage: %s <options> <infile> [<outfile>]\n" + +"\nOptions:\n" +" -h display this help and exit\n" +" -V display the version number and copyright\n" + +"\nlm2latex "L2L_VERSION_STRING L2L_VERSION_EXTRA", "PACKAGE_URL"\n", +basename(name)); + exit(status); +} /* exit_usage */ + +static void +exit_version(void) +{ + printf("lm2latex version "L2L_VERSION_STRING L2L_VERSION_EXTRA", " + "built "BUILD_DATE"\n" + "Copyright (C) 2010 "PACKAGE_BUGREPORT"\n" + + "\nThis is free software under the terms of the BSD license, see " + "the source for\ncopying conditions. There is NO WARRANTY; not " + "even for MERCHANTABILITY or\nFITNESS FOR A PARTICULAR " + "PURPOSE.\n"); + exit(0); +} /* exit_version */ + +int +main(int argc, char **argv) +{ + char *infile = NULL, *outfile = NULL; + FILE *in_fh, *out_fh; + int args; + + while (42) { + int opt = getopt(argc, argv, "hV"); + + if (-1 == opt) + break; + + switch (opt) { + case 'h': + exit_usage(argv[0], 0); + break; + case 'V': + exit_version(); + break; + default: + exit_usage(argv[0], 1); + } + } + + args = argc - optind; + if ((0 < args) && (args <= 2)) { + infile = argv[optind]; + + if (1 < args) + outfile = argv[optind + 1]; + else + outfile = "-"; + } + else + exit_usage(argv[0], 1); + + if (! strcmp(infile, "-")) + in_fh = stdin; + else + in_fh = fopen(infile, "r"); + + if (! in_fh) { + fprintf(stderr, "lm2latex: FATAL: Failed to open ``%s'' " + "for reading: %s\n", infile, strerror(errno)); + return 1; + } + + if (! strcmp(outfile, "-")) + out_fh = stdout; + else + out_fh = fopen(outfile, "w"); + + if (! out_fh) { + fprintf(stderr, "lm2latex: FATAL: Failed to open ``%s'' " + "for writing: %s\n", outfile, strerror(errno)); + return 1; + } + + l2l_convert_file_fh(in_fh, out_fh); + + if (in_fh != stdin) + fclose(in_fh); + if (out_fh != stdout) + fclose(out_fh); + return 0; +} /* main */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/version-gen.sh b/version-gen.sh new file mode 100755 index 0000000..77457be --- /dev/null +++ b/version-gen.sh @@ -0,0 +1,40 @@ +#! /bin/sh + +DEFAULT_VERSION="0.0.0.git" + +VERSION="$( git describe --tags 2> /dev/null \ + | sed -e 's/lm2latex-//' || true )" + +if test -z "$VERSION"; then + VERSION="$DEFAULT_VERSION" +else + git update-index -q --refresh || true + if test -n "$( git diff-index --name-only HEAD || true )"; then + VERSION="$VERSION-dirty" + fi +fi + +VERSION="$( echo "$VERSION" | sed -e 's/-/./g' )" +echo -n "$VERSION" + +OLD_VERSION="" +if test -e version; then + OLD_VERSION=$( sed -ne 's/^VERSION="\(.*\)"/\1/p' version ) +fi + +if test "$OLD_VERSION" != "$VERSION"; then + VERSION_MAJOR=$( echo $VERSION | cut -d'.' -f1 ) + VERSION_MINOR=$( echo $VERSION | cut -d'.' -f2 ) + VERSION_PATCH=$( echo $VERSION | cut -d'.' -f3 ) + VERSION_EXTRA="\"$( echo $VERSION | cut -d'.' -f4- )\"" + test -z "$VERSION_EXTRA" || VERSION_EXTRA=".$VERSION_EXTRA" + ( + echo "VERSION=\"$VERSION\"" + echo "VERSION_MAJOR=$VERSION_MAJOR" + echo "VERSION_MINOR=$VERSION_MINOR" + echo "VERSION_PATCH=$VERSION_PATCH" + echo "VERSION_EXTRA=\"$VERSION_EXTRA\"" + echo "VERSION_STRING=\"$VERSION_MAJOR.$VERSION_MINOR.$VERSION_PATCH\"" + ) > version +fi +