diff --git a/.travis.yml b/.travis.yml index c270000..8baa452 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ jobs: apt: packages: - libiodbc2-dev + - gawk env: - CONFIGURE_FLAGS="--with-iodbc=/usr --disable-glib" - compiler: clang @@ -18,6 +19,7 @@ jobs: packages: - libiodbc2-dev - libglib2.0-dev + - gawk env: - CONFIGURE_FLAGS="--with-iodbc=/usr --enable-glib" - compiler: clang @@ -26,6 +28,7 @@ jobs: apt: packages: - unixodbc-dev + - gawk env: - CONFIGURE_FLAGS="--with-unixodbc=/usr --disable-glib" - compiler: clang @@ -35,6 +38,7 @@ jobs: packages: - unixodbc-dev - libglib2.0-dev + - gawk env: - CONFIGURE_FLAGS="--with-unixodbc=/usr --enable-glib" - compiler: gcc @@ -43,6 +47,7 @@ jobs: apt: packages: - libiodbc2-dev + - gawk env: - CONFIGURE_FLAGS="--with-iodbc=/usr --disable-glib" - compiler: gcc @@ -51,6 +56,7 @@ jobs: apt: packages: - unixodbc-dev + - gawk env: - CONFIGURE_FLAGS="--with-unixodbc=/usr --disable-glib" - compiler: gcc-10 @@ -62,6 +68,7 @@ jobs: packages: - gcc-10 - libiodbc2-dev + - gawk env: - CONFIGURE_FLAGS="--with-iodbc=/usr --disable-glib" - compiler: gcc-10 @@ -73,6 +80,7 @@ jobs: packages: - gcc-10 - unixodbc-dev + - gawk env: - CONFIGURE_FLAGS="--with-unixodbc=/usr --disable-glib" - compiler: clang @@ -83,6 +91,7 @@ jobs: packages: - libiodbc - bison + - gawk env: - CONFIGURE_FLAGS="--with-iodbc=/usr/local/opt --disable-glib" - YACC="/usr/local/opt/bison/bin/bison" @@ -95,6 +104,7 @@ jobs: - libiodbc - glib - bison + - gawk env: - CONFIGURE_FLAGS="--with-iodbc=/usr/local/opt --enable-glib" - YACC="/usr/local/opt/bison/bin/bison" @@ -106,6 +116,7 @@ jobs: packages: - unixodbc - bison + - gawk env: - CONFIGURE_FLAGS="--with-unixodbc=/usr/local/opt --disable-glib" - YACC="/usr/local/opt/bison/bin/bison" @@ -118,6 +129,7 @@ jobs: - unixodbc - glib - bison + - gawk env: - CONFIGURE_FLAGS="--with-unixodbc=/usr/local/opt --enable-glib" - YACC="/usr/local/opt/bison/bin/bison" @@ -129,6 +141,7 @@ jobs: packages: - libiodbc - bison + - gawk env: - CONFIGURE_FLAGS="--with-iodbc=/usr/local/opt --disable-glib" - YACC="/usr/local/opt/bison/bin/bison" @@ -140,6 +153,7 @@ jobs: packages: - unixodbc - bison + - gawk env: - CONFIGURE_FLAGS="--with-unixodbc=/usr/local/opt --disable-glib" - YACC="/usr/local/opt/bison/bin/bison" @@ -148,7 +162,7 @@ before_script: - autoreconf -i -f -Wno-portability script: - - ./configure --disable-man --disable-silent-rules $CONFIGURE_FLAGS + - ./configure --disable-silent-rules $CONFIGURE_FLAGS - make - ./src/util/mdb-array test/data/ASampleDatabase.accdb "Asset Items" - ./src/util/mdb-array test/data/nwind.mdb "Customers" diff --git a/README.md b/README.md index 7eaae21..a015025 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ If you want to build the ODBC driver, you'll need `unixodbc-dev` (version 2.2.10 or above) or [iodbc](http://www.iodbc.org/dataspace/doc/iodbc/wiki/iodbcWiki/WelcomeVisitors). If you want to build man pages, you'll need -[txt2man](https://github.com/mvertes/txt2man). +[GNU awk](https://www.gnu.org/software/gawk/). If you want to generate the html version of the docbook, you'll need [openjade](http://openjade.sourceforge.net) and basic dsl catalogs. @@ -102,7 +102,21 @@ If you want to generate the html version of the docbook, you'll need # Installation -Last version is available at https://github.com/mdbtools/mdbtools +Latest version is available at https://github.com/mdbtools/mdbtools + +## Debian + +``` +apt-get install mdbtools +``` + +## Homebrew + +```bash +brew install mdbtools +``` + +## From source ```bash $ autoreconf -i -f -Wno-portability @@ -110,7 +124,7 @@ $ autoreconf -i -f -Wno-portability If you want to build the html version of the docbook documentation, you need to set the environment variable `DOCBOOK_DSL` to the modular dsl translation file. -For exemple, before configure, you need something like: +For example, before configure, you need something like: ```bash $ export DOCBOOK_DSL=/usr/share/sgml/docbook/stylesheet/dsssl/modular/html/docbook.dsl diff --git a/configure.ac b/configure.ac index 6c50adb..d5dfa74 100644 --- a/configure.ac +++ b/configure.ac @@ -285,8 +285,8 @@ AC_ARG_ENABLE(man, AS_HELP_STRING([--disable-man], [disable man generation]), enable_man="$enableval", [enable_man=yes]) if test "$enable_man" = yes; then - if ! which txt2man > /dev/null; then - AC_MSG_ERROR([Could not find txt2man script. Install it or configure with --disable-man if you are not interrested in manuals.]) + if ! which gawk > /dev/null; then + AC_MSG_ERROR([Could not find GNU awk. Install it or configure with --disable-man if you are not interested in manuals.]) fi fi AM_CONDITIONAL(ENABLE_MAN, test "$enable_man" = yes) diff --git a/doc/Makefile.am b/doc/Makefile.am index f80ff01..08f846d 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,5 +1,5 @@ SHELL = /bin/sh -TXT2MAN = txt2man +TXT2MAN = ./txt2man PRODUCT = MDBTools # To make the userguide, export DOCBOOK_DSL TO point to docbook.dsl. diff --git a/doc/txt2man b/doc/txt2man new file mode 100755 index 0000000..05072e3 --- /dev/null +++ b/doc/txt2man @@ -0,0 +1,409 @@ +#!/bin/sh + +# Copyright (C) 2001, 2002, 2003 Marc Vertes + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# release 1.7.1 + +usage() +{ +cat << EOT +NAME + txt2man - convert flat ASCII text to man page format +SYNOPSIS + txt2man [-hpTX] [-t mytitle] [-P pname] [-r rel] [-s sect] + [-v vol] [-I txt] [-B txt] [-d date] [ifile] +DESCRIPTION + txt2man converts the input text into nroff/troff standard man(7) + macros used to format Unix manual pages. Nice pages can be generated + specially for commands (section 1 or 8) or for C functions reference + (sections 2, 3), with the ability to recognize and format command and + function names, flags, types and arguments. + + txt2man is also able to recognize and format sections, paragraphs, + lists (standard, numbered, description, nested), cross references and + literal display blocks. + + If input file ifile is omitted, standard input is used. Result is + displayed on standard output. + + Here is how text patterns are recognized and processed: + Sections These headers are defined by a line in upper case, starting + column 1. If there is one or more leading spaces, a + sub-section will be generated instead. Optionally, the + Section name can be preceded by a blank line. This is useful + for a better visualization of the source text to be used to + generate the manpage. + Paragraphs They must be separated by a blank line, and left aligned. + Alternatively two blank spaces can be used to produce the + same result. This option will provide a better visualization + of the source text to be used to generate the manpage. + Tag list The item definition is separated from the item description + by at least 2 blank spaces, even before a new line, if + definition is too long. Definition will be emphasized + by default. + Bullet list + Bullet list items are defined by the first word being "-" + or "*" or "o". + Enumerated list + The first word must be a number followed by a dot. + Literal display blocks + This paragraph type is used to display unmodified text, + for example source code. It must be separated by a blank + line and be indented by a TAB. It is primarily used to format + unmodified source code. It will be printed using fixed font + whenever possible (troff). + Cross references + A cross reference (another man page) is defined by a word + followed by a number in parenthesis. + + Special sections: + NAME The function or command name and short description are set in + this section. + SYNOPSIS This section receives a special treatment to identify command + name, flags and arguments, and propagate corresponding + attributes later in the text. If a C like function is recognized + (word immediately followed by an open parenthesis), txt2man will + print function name in bold font, types in normal font, and + variables in italic font. The whole section will be printed using + a fixed font family (courier) whenever possible (troff). + + It is a good practice to embed documentation into source code, by using + comments or constant text variables. txt2man allows one to do that, keeping + the document source readable, usable even without further formatting + (i.e. for online help) and easy to write. The result is high quality + and standard complying document. +OPTIONS + -h The option -h displays help. + -d date Set date in header. Defaults to current date. + -P pname Set pname as project name in header. Default to uname -s. + -p Probe title, section name and volume. + -t mytitle Set mytitle as title of generated man page. + -r rel Set rel as project name and release. + -s sect Set sect as section in heading, usually a value from 1 to 8. + -v vol Set vol as volume name, i.e. "Unix user 's manual". + -I txt Italicize txt in output. Can be specified more than once. + -B txt Emphasize (bold) txt in output. Can be specified more than once. + -T Text result previewing using PAGER, usually more(1). + -X X11 result previewing using gxditview(1). +ENVIRONMENT + PAGER name of paging command, usually more(1), or less(1). If not set + falls back to more(1). + SOURCE_DATE_EPOCH Unix timestamp that is used for date in header instead + of current date. +EXAMPLES + Try this command to format this text itself: + + $ txt2man -h 2>&1 | txt2man -T + + The following command will generate a manpage level 1 to foo-1.1.0 program, + from foo.txt file, used as source code to previously mentioned manpage: + + $ txt2man -d "15 May 2016" -t foo -r foo-1.1.0 -s 1 -v "show stars on screen" foo.txt > foo.1 +HINTS + To obtain an overall good formatting of output document, keep paragraphs + indented correctly. If you have unwanted bold sections, search for + multiple spaces between words, which are used to identify a tag list + (term followed by a description). Choose also carefully the name of + command line or function parameters, as they will be emphasized each + time they are encountered in the document. +SEE ALSO + man(1), mandoc(7), rman(1), groff(1), more(1), gxditview(1), troff(1). +BUGS + - Automatic probe (-p option) works only if input is a regular file (i.e. + not stdin). +AUTHOR + Marc Vertes +EOT +} + +sys=$(uname -s) +rel= +volume= +section= +title=untitled +doprobe= +itxt= +btxt= +post=cat +while getopts :d:hpTXr:s:t:v:P:I:B: opt +do + case $opt in + (d) date=$OPTARG;; + (r) rel=$OPTARG;; + (t) title=$OPTARG;; + (s) section=$OPTARG;; + (v) volume=$OPTARG;; + (P) sys=$OPTARG;; + (p) doprobe=1;; + (I) itxt="$OPTARG§$itxt";; + (B) btxt="$OPTARG§$btxt";; + (T) post="groff -mandoc -Tlatin1 | ${PAGER:-more}";; + (X) post="groff -mandoc -TX100-12 -rS12";; + (*) usage; exit;; + esac +done +shift $(($OPTIND - 1)) + +# Compatibility wrapper for BSD/GNU date, for parsing dates +if date -j >/dev/null 2>&1; then + pdate() { date -u -j -f '@%s' "$@"; } +else + pdate() { date -u -d "$@"; } +fi + +if [ -n "$SOURCE_DATE_EPOCH" ]; then + date=$(LC_ALL=C pdate "@$SOURCE_DATE_EPOCH" +'%d %B %Y') +fi +date=${date:-$(LC_ALL=C date -u +'%d %B %Y')} + +if test "$doprobe" +then + title=${1##*/}; title=${title%.txt} + if grep -q '#include ' $1 + then + section=${section:-3} + volume=${volume:-"$sys Programmer's Manual"} + else + section=${section:-1} + volume=${volume:-"$sys Reference Manual"} + fi + # get release from path + rel=${rel:-"$(pwd | sed 's:/.*[^0-9]/::g; s:/.*::g')"} +fi + +head="\" Text automatically generated by txt2man +.TH $title $section \"$date\" \"$rel\" \"$volume\"" + +# All tabs converted to spaces +expand $* | +# gawk is needed because use of non standard regexp +gawk --re-interval -v head="$head" -v itxt="$itxt" -v btxt="$btxt" ' +BEGIN { + print ".\\" head + avar[1] = btxt; avar[2] = itxt + for (k in avar) { + mark = (k == 1) ? "\\fB" : "\\fI" + split(avar[k], tt, "§") + for (i in tt) + if (tt[i] != "") + subwords["\\<" tt[i] "\\>"] = mark tt[i] "\\fP" + for (i in tt) + delete tt[i] + } + for (k in avar) + delete avar[k] +} +{ + # to avoid some side effects in regexp + gsub(/\.\.\./, "\\.\\.\\.") + # remove spaces in empty lines + sub(/^ +$/,"") +} +/^[:space:]*[[:upper:][:digit:]]+[[:upper:][:space:][:digit:][:punct:]]+$/ { + # Section header + if ((in_bd + 0) == 1) { + in_bd = 0 + print ".fam T\n.fi" + } + if (section == "SYNOPSIS") { + print ".fam T\n.fi" + type["SYNOPSIS"] = "" + } + if ($0 ~/^[^[:space:]]/) + print ".SH " $0 + else + print ".SS" $0 + sub(/^ +/, "") + section = $0 + if (section == "SYNOPSIS") { + print ".nf\n.fam C" + in_bd = 1 + } + ls = 0 # line start index + pls = 0 # previous line start index + pnzls = 0 # previous non zero line start index + ni = 0 # indent level + ind[0] = 0 # indent offset table + prevblankline = 0 + next +} +{ + # Compute line start index, handle start of example display block + pls = ls + if (ls != 0) + pnzls = ls + match($0, /[^ ]/) + ls = RSTART + if (in_bd == 0 && pls == 0 && pnzls > 0 && ls > pnzls && $1 !~ /^[\-\*o]$|^[0-9]+\.$/) { + # example display block + if (prevblankline == 1) { + print ".PP" + prevblankline = 0 + } + print ".nf\n.fam C" + in_bd = 1 + eoff = ls + } + if (ls > 0 && ind[0] == 0) + ind[0] = ls +} +(in_bd + 0) == 1 { + # In block display + if (section == "SYNOPSIS") + ; + else if (ls != 0 && ls < eoff) { + # End of litteral display block + in_bd = 0 + print ".fam T\n.fi" + } else { print; next } +} +section == "NAME" { + $1 = "\\fB" $1 + sub(/ \- /, " \\fP- ") +} +section == "SYNOPSIS" { + # Identify arguments of fcts and cmds + if (type["SYNOPSIS"] == "") { + if ($0 ~ /\(/) + type["SYNOPSIS"] = "fct" + else if ($1 == "struct" || $2 == "struct") + type["SYNOPSIS"] = "struct" + else if ($1 && $1 !~ /^#|typedef|struct|union|enum/) + type["SYNOPSIS"] = "cmd" + } + if (type["SYNOPSIS"] == "cmd") { + # Line is a command line + if ($1 !~ /^\[/) { + b = $1 + sub(/^\*/, "", b) + subwords["\\<" b "\\>"] = "\\fB" b "\\fP" + } + for (i = 2; i <= NF; i++) { + a = $i + gsub(/[\[\]\|]/, "", a) + if (a ~ /^[^\-]/) + subwords["\\<" a "\\>"] = "\\fI" a "\\fP" + } + } else if (type["SYNOPSIS"] == "fct") { + # Line is a C function definition + if ($1 == "typedef") { + if ($0 !~ /\(\*/) + subwords["\\<" $2 "\\>"] = "\\fI" $2 "\\fP" + } else if ($1 == "#define") + subwords["\\<" $2 "\\>"] = "\\fI" $2 "\\fP" + for (i = 1; i <= NF; i++) { + if ($i ~ /[,\)];*$/) { + a = $i + sub(/.*\(/, "", a) + gsub(/\W/, "", a) + subwords["\\<" a "\\>"] = "\\fI" a "\\fP" + } + } + } +} +{ + # protect dots inside words + while ($0 ~ /\w\.\w/) + sub(/\./, "_dOt_") + # identify func calls and cross refs + for (i = 1; i <= NF; i++) { + b = $i + sub(/^\*/, "", b) + if ((a = index(b, ")(")) > 3) { + w = substr(b, 3, a - 3) + subwords["\\<" w "\\>"] = "\\fI" w "\\fP" + } + if ((a = index(b, "(")) > 1) { + w = substr(b, 1, a - 1) + subwords["\\<" w "\\("] = "\\fB" w "\\fP(" + } + } + # word attributes + n = asorti(subwords, indices) + for (i = 1; i <= n; i++) + gsub(indices[i], subwords[indices[i]]) + # shell options + gsub(/\B\-+\w+(\-\w+)*/, "\\fB&\\fP") + # unprotect dots inside words + gsub(/_dOt_/, ".") + + if (section == "SYNOPSIS") { + sub(/^ /, "") + print + next + } + if (match($0, /[^ ] +/) > 0) { + # tag list item + adjust_indent() + tag = substr($0, 1, RSTART) + sub(/^ */, "", tag) + if (RSTART+RLENGTH < length()) + $0 = substr($0, RSTART + RLENGTH) + else + $0 = "" + print ".TP\n.B" + print tag + prevblankline = 0 + if (NF == 0) + next + } else if ($1 == "-"||$1 == "o"||$1 == "*") { + # bullet list item + adjust_indent() + print ".IP \\(bu 3" + prevblankline = 0 + $1 = "" + } else if ($1 ~ /^[0-9]+[\).]$/) { + # enum list item + adjust_indent() + print ".IP " $1 " 4" + prevblankline = 0 + $1 = "" + } else if (pls == 0) { + # new paragraph + adjust_indent() + } else if (NF == 0) { + # blank line + prevblankline = 1 + next + } else + prevblankline = 0 + # flush vertical space + if (prevblankline == 1) { + print ".PP" + prevblankline = 0 + } + if (section != "SYNOPSIS" || $0 ~ /^ {1,4}/) + sub(/ */,"") + # Protect lines starting by simple quotes + sub(/^'\''/, "\\(cq") + print +} + +function adjust_indent() +{ + if (ls > ind[ni]) { + ind[++ni] = ls + print ".RS" + } else if (ls < ind[ni]) { + while (ls < ind[ni]) { + ni-- + print ".RE" + } + } +} +' | eval $post