author | Sebastian Harl <sh@tokkee.org> | |
Sun, 13 Jun 2010 20:42:14 +0000 (22:42 +0200) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Sun, 13 Jun 2010 20:42:14 +0000 (22:42 +0200) |
So far, the tool is able to parse most (all but tables) of the Linux-Magazin
markup language and output an appropriate LaTeX file.
markup language and output an appropriate LaTeX file.
14 files changed:
.gitignore | [new file with mode: 0644] | patch | blob |
COPYING | [new file with mode: 0644] | patch | blob |
INSTALL | [new file with mode: 0644] | patch | blob |
Makefile.am | [new file with mode: 0644] | patch | blob |
README | [new file with mode: 0644] | patch | blob |
autogen.sh | [new file with mode: 0755] | patch | blob |
configure.ac | [new file with mode: 0644] | patch | blob |
src/Makefile.am | [new file with mode: 0644] | patch | blob |
src/l2l.c | [new file with mode: 0644] | patch | blob |
src/l2l.h | [new file with mode: 0644] | patch | blob |
src/l2l_features.h.in | [new file with mode: 0644] | patch | blob |
src/l2l_scanner.l | [new file with mode: 0644] | patch | blob |
src/lm2latex.c | [new file with mode: 0644] | patch | blob |
version-gen.sh | [new file with mode: 0755] | patch | blob |
diff --git a/.gitignore b/.gitignore
--- /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
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,24 @@
+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.
+
diff --git a/INSTALL b/INSTALL
--- /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
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = src
+
+EXTRA_DIST = autogen.sh version-gen.sh
+
diff --git a/README b/README
--- /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=<path> to `make install', <path> will be
+ prefixed to all installation directories. This might be useful when creating
+ packages for lm2latex.
+
+Author
+------
+
+ Sebastian "tokkee" Harl <sh@tokkee.org>
+
diff --git a/autogen.sh b/autogen.sh
--- /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
--- /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 <sh@tokkee.org>
+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 <sh@tokkee.org>], [],
+ [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 <<EOF;
+
+$PACKAGE_NAME has been configured successfully.
+
+Run 'make' to compile the software and use 'make install' to
+install the package into $prefix.
+
+Configuration summary:
+
+ package version: $PACKAGE_VERSION
+ build date: `date --utc '+%F %T'` (UTC)
+
+Please report bugs to $PACKAGE_BUGREPORT.
+
+EOF
+
diff --git a/src/Makefile.am b/src/Makefile.am
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,48 @@
+AM_CFLAGS = @STRICT_CFLAGS@
+
+# we cannot set this as '%option header-file', since flex is called thru the
+# ylwrap wrapper script, which runs in a temporary directory
+AM_LFLAGS = --header-file=@abs_srcdir@/l2l_scanner.h
+
+BUILT_SOURCES = l2l_features.h l2l_scanner.l
+
+CLEANFILES = l2l_features.h l2l_scanner.c
+
+l2l_scanner.h: l2l_scanner.c
+
+# build this as a separate private library to be able to use different CFLAGS
+noinst_LTLIBRARIES = libl2l_scanner.la
+libl2l_scanner_la_SOURCES = l2l_scanner.l
+libl2l_scanner_la_CFLAGS = -Wall -Werror \
+ -Wno-unused-function -Wno-unused-variable \
+ -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=600
+
+include_HEADERS = l2l.h l2l_features.h
+lib_LTLIBRARIES = libl2l.la
+
+libl2l_la_SOURCES = l2l.c l2l.h l2l_features.h
+libl2l_la_LDFLAGS = -version-info 0:0:0
+libl2l_la_LIBADD = libl2l_scanner.la
+
+bin_PROGRAMS = lm2latex
+
+lm2latex_SOURCES = lm2latex.c l2l.h
+lm2latex_CFLAGS = $(AM_CFLAGS) \
+ -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\""
+lm2latex_LDADD = libl2l.la
+
+../version: FORCE
+ @# As a side-effect, this updates ../version.
+ @echo Building $(PACKAGE_NAME) version $$( cd .. && ./version-gen.sh )
+
+l2l_features.h: l2l_features.h.in ../version
+ source ../version; sed \
+ -e "s/@L2L_VERSION_MAJOR@/$$VERSION_MAJOR/g" \
+ -e "s/@L2L_VERSION_MINOR@/$$VERSION_MINOR/g" \
+ -e "s/@L2L_VERSION_PATCH@/$$VERSION_PATCH/g" \
+ -e "s/@L2L_VERSION_EXTRA@/$$VERSION_EXTRA/g" \
+ -e "s/@L2L_VERSION_STRING@/$$VERSION_STRING/g" \
+ l2l_features.h.in > l2l_features.h
+
+.PHONY: FORCE
+
diff --git a/src/l2l.c b/src/l2l.c
--- /dev/null
+++ b/src/l2l.c
@@ -0,0 +1,161 @@
+/*
+ * lm2latex - src/l2l.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 -- core library.
+ */
+
+#include "l2l.h"
+#include "l2l_scanner.h"
+#include "l2l_features.h"
+
+#include <assert.h>
+
+#include <stdio.h>
+
+/*
+ * 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
--- /dev/null
+++ b/src/l2l.h
@@ -0,0 +1,54 @@
+/*
+ * lm2latex - src/l2l.h
+ * 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 -- core library.
+ */
+
+#ifndef L2L_H
+#define L2L_H 1
+
+#include <stdio.h>
+
+#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
--- /dev/null
+++ b/src/l2l_features.h.in
@@ -0,0 +1,69 @@
+/*
+ * lm2latex - src/l2l_features.h
+ * 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.
+ */
+
+/*
+ * 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
--- /dev/null
+++ b/src/l2l_scanner.l
@@ -0,0 +1,675 @@
+/*
+ * lm2latex - src/l2l_scanner.l
+ * 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 -- LM markup scanner.
+ */
+
+%{
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include <ctype.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+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("@#:")); }
+
+<INITIAL,box,caption,box_caption,command,headertxt,itemize,title>{
+ /* 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);
+}
+
+<url>\<[uU]> {
+ L2L_YY_APPEND_OR_ECHO(l2l_buf_ptr, "}");
+ BEGIN(l2l_last_yystart);
+}
+
+<url>.|\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);
+}
+
+<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);
+}
+
+<headertxt>{COMMENT} { /* ignore */ }
+
+<headertxt>.|\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);
+}
+
+<itemize>({WHITESPACE}|\n)*\n\n |
+<itemize>({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 */
+<itemize>({WHITESPACE}|\n)*\n{WHITESPACE}*\*{WHITESPACE}* {
+ fprintf(yyout, "\n\\item ");
+}
+<itemize>({WHITESPACE}|\n)*\n\n({WHITESPACE}{2,}|\t) ECHO;
+
+<itemize>. ECHO;
+
+@ZT:{WHITESPACE}* {
+ fprintf(yyout, "\\subsection*{");
+ BEGIN(command);
+}
+
+<command>({WHITESPACE}|\n)+{ANY_COMMAND} {
+ fprintf(yyout, "}");
+ yyless(0);
+ BEGIN(l2l_last_yystart);
+}
+
+<command>. ECHO;
+
+@LI:{WHITESPACE}*\n? {
+ /* \xb7 = MIDDLE DOT (iso-8859-1 and iso-8859-15) */
+ fprintf(yyout, "\\begin{lstlisting}[escapechar=\xb7]\n");
+ BEGIN(listing);
+}
+
+<listing>\n*{ANY_COMMAND} {
+ fprintf(yyout, "\n\\end{lstlisting}");
+ yyless(0);
+ BEGIN(l2l_last_yystart);
+}
+
+<listing>\<§§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;
+ }
+}
+
+<listing>§§\n /* ignore => lstlisting will insert appropriate arrows */;
+
+<listing>. 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);
+}
+
+<box>@(KE|L):{WHITESPACE}* {
+ fprintf(yyout, "\\end{figure}");
+ l2l_scanner_state = L2L_BODY;
+ l2l_last_yystart = INITIAL;
+ BEGIN(l2l_last_yystart);
+}
+
+<caption,box_caption>{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);
+}
+
+<caption,box_caption>{COMMENT} { /* ignore */ }
+
+<caption,box_caption>.|\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);
+}
+
+<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
--- /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
--- /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
+