diff -Nurd gettext-0.12.1/gettext-tools/src/FILES gettext-0.12.1.ocaml/gettext-tools/src/FILES
--- gettext-0.12.1/gettext-tools/src/FILES 2003-04-29 12:00:15.000000000 +0200
+++ gettext-0.12.1.ocaml/gettext-tools/src/FILES 2003-07-03 18:52:19.000000000 +0200
@@ -177,6 +177,7 @@
format-ycp.c Format string handling for YCP.
format-tcl.c Format string handling for Tcl.
format-php.c Format string handling for PHP.
+format-ocaml.c Format string handling for Objective Caml.
format.c Table of the language dependent format string handlers.
+-------------- The 'msgfmt' program
@@ -239,6 +240,9 @@
| x-php.h
| x-php.c
| String extractor for PHP.
+| x-ocaml.h
+| x-ocaml.c
+| String extractor for Objective Caml.
| x-rst.h
| x-rst.c
| String extractor from .rst files, for Object Pascal.
diff -Nurd gettext-0.12.1/gettext-tools/src/Makefile.am gettext-0.12.1.ocaml/gettext-tools/src/Makefile.am
--- gettext-0.12.1/gettext-tools/src/Makefile.am 2003-04-29 12:05:37.000000000 +0200
+++ gettext-0.12.1.ocaml/gettext-tools/src/Makefile.am 2003-07-16 22:00:23.000000000 +0200
@@ -42,7 +42,7 @@
write-mo.h read-java.h write-java.h read-tcl.h write-tcl.h po-time.h \
plural-table.h format.h xgettext.h x-c.h x-po.h x-python.h x-lisp.h x-elisp.h \
x-librep.h x-smalltalk.h x-java.h x-properties.h x-awk.h x-ycp.h x-tcl.h \
-x-php.h x-rst.h x-glade.h
+x-php.h x-rst.h x-glade.h x-ocaml.h
EXTRA_DIST += FILES project-id ChangeLog.0
@@ -93,7 +93,7 @@
FORMAT_SOURCE = format.c format-invalid.h \
format-c.c format-python.c format-lisp.c format-elisp.c format-librep.c \
format-java.c format-awk.c format-pascal.c format-ycp.c format-tcl.c \
-format-php.c
+format-php.c format-ocaml.c
# libgettextsrc contains all code that is needed by at least two programs.
libgettextsrc_la_SOURCES = \
@@ -119,7 +119,7 @@
msgunfmt_SOURCES = msgunfmt.c read-mo.c read-java.c read-tcl.c
xgettext_SOURCES = xgettext.c \
x-c.c x-po.c x-python.c x-lisp.c x-elisp.c x-librep.c x-smalltalk.c \
- x-java.l x-awk.c x-ycp.c x-tcl.c x-php.c x-rst.c x-glade.c
+ x-java.l x-awk.c x-ycp.c x-tcl.c x-php.c x-rst.c x-glade.c x-ocaml.c
msgattrib_SOURCES = msgattrib.c
msgcat_SOURCES = msgcat.c
msgcomm_SOURCES = msgcomm.c
diff -Nurd gettext-0.12.1/gettext-tools/src/Makefile.in gettext-0.12.1.ocaml/gettext-tools/src/Makefile.in
--- gettext-0.12.1/gettext-tools/src/Makefile.in 2003-05-22 15:41:24.000000000 +0200
+++ gettext-0.12.1.ocaml/gettext-tools/src/Makefile.in 2003-07-16 22:04:36.000000000 +0200
@@ -250,7 +250,7 @@
write-mo.h read-java.h write-java.h read-tcl.h write-tcl.h po-time.h \
plural-table.h format.h xgettext.h x-c.h x-po.h x-python.h x-lisp.h x-elisp.h \
x-librep.h x-smalltalk.h x-java.h x-properties.h x-awk.h x-ycp.h x-tcl.h \
-x-php.h x-rst.h x-glade.h
+x-php.h x-rst.h x-glade.h x-ocaml.h
localedir = $(datadir)/locale
@@ -286,7 +286,7 @@
FORMAT_SOURCE = format.c format-invalid.h \
format-c.c format-python.c format-lisp.c format-elisp.c format-librep.c \
format-java.c format-awk.c format-pascal.c format-ycp.c format-tcl.c \
-format-php.c
+format-php.c format-ocaml.c
# libgettextsrc contains all code that is needed by at least two programs.
@@ -314,7 +314,7 @@
msgunfmt_SOURCES = msgunfmt.c read-mo.c read-java.c read-tcl.c
xgettext_SOURCES = xgettext.c \
x-c.c x-po.c x-python.c x-lisp.c x-elisp.c x-librep.c x-smalltalk.c \
- x-java.l x-awk.c x-ycp.c x-tcl.c x-php.c x-rst.c x-glade.c
+ x-java.l x-awk.c x-ycp.c x-tcl.c x-php.c x-rst.c x-glade.c x-ocaml.c
msgattrib_SOURCES = msgattrib.c
msgcat_SOURCES = msgcat.c
@@ -439,7 +439,7 @@
dir-list.lo str-list.lo
am__objects_2 = format.lo format-c.lo format-python.lo format-lisp.lo \
format-elisp.lo format-librep.lo format-java.lo format-awk.lo \
- format-pascal.lo format-ycp.lo format-tcl.lo format-php.lo
+ format-pascal.lo format-ycp.lo format-tcl.lo format-php.lo format-ocaml.lo
am_libgettextsrc_la_OBJECTS = $(am__objects_1) read-po.lo \
write-properties.lo write-po.lo msgl-ascii.lo msgl-iconv.lo \
msgl-equal.lo msgl-cat.lo msgl-english.lo file-list.lo \
@@ -517,7 +517,7 @@
xgettext-x-java.$(OBJEXT) xgettext-x-awk.$(OBJEXT) \
xgettext-x-ycp.$(OBJEXT) xgettext-x-tcl.$(OBJEXT) \
xgettext-x-php.$(OBJEXT) xgettext-x-rst.$(OBJEXT) \
- xgettext-x-glade.$(OBJEXT)
+ xgettext-x-glade.$(OBJEXT) xgettext-x-ocaml.$(OBJEXT)
xgettext_OBJECTS = $(am_xgettext_OBJECTS)
xgettext_DEPENDENCIES = ../libuniname/libuniname.a libgettextsrc.la
@@ -1045,6 +1045,15 @@
xgettext-x-php.lo: x-php.c
$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xgettext_CFLAGS) $(CFLAGS) -c -o xgettext-x-php.lo `test -f 'x-php.c' || echo '$(srcdir)/'`x-php.c
+xgettext-x-ocaml.o: x-ocaml.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xgettext_CFLAGS) $(CFLAGS) -c -o xgettext-x-ocaml.o `test -f 'x-ocaml.c' || echo '$(srcdir)/'`x-ocaml.c
+
+xgettext-x-ocaml.obj: x-ocaml.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xgettext_CFLAGS) $(CFLAGS) -c -o xgettext-x-ocaml.obj `if test -f 'x-ocaml.c'; then $(CYGPATH_W) 'x-ocaml.c'; else $(CYGPATH_W) '$(srcdir)/x-ocaml.c'; fi`
+
+xgettext-x-ocaml.lo: x-ocaml.c
+ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xgettext_CFLAGS) $(CFLAGS) -c -o xgettext-x-ocaml.lo `test -f 'x-ocaml.c' || echo '$(srcdir)/'`x-ocaml.c
+
xgettext-x-rst.o: x-rst.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xgettext_CFLAGS) $(CFLAGS) -c -o xgettext-x-rst.o `test -f 'x-rst.c' || echo '$(srcdir)/'`x-rst.c
diff -Nurd gettext-0.12.1/gettext-tools/src/Makefile.msvc gettext-0.12.1.ocaml/gettext-tools/src/Makefile.msvc
--- gettext-0.12.1/gettext-tools/src/Makefile.msvc 2003-05-18 13:21:29.000000000 +0200
+++ gettext-0.12.1.ocaml/gettext-tools/src/Makefile.msvc 2003-07-16 22:06:25.000000000 +0200
@@ -139,13 +139,14 @@
format-pascal.obj \
format-ycp.obj \
format-tcl.obj \
- format-php.obj
+ format-php.obj \
+ format-ocaml.obj
msgcmp_OBJECTS = msgcmp.obj
msgfmt_OBJECTS = msgfmt.obj write-mo.obj write-java.obj write-tcl.obj plural-eval.obj
msgmerge_OBJECTS = msgmerge.obj
msgunfmt_OBJECTS = msgunfmt.obj read-mo.obj read-java.obj read-tcl.obj
-xgettext_OBJECTS = xgettext.obj x-c.obj x-po.obj x-python.obj x-lisp.obj x-elisp.obj x-librep.obj x-smalltalk.obj x-java.obj x-awk.obj x-ycp.obj x-tcl.obj x-php.obj x-rst.obj x-glade.obj
+xgettext_OBJECTS = xgettext.obj x-c.obj x-po.obj x-python.obj x-lisp.obj x-elisp.obj x-librep.obj x-smalltalk.obj x-java.obj x-awk.obj x-ycp.obj x-tcl.obj x-php.obj x-rst.obj x-glade.obj x-ocaml.obj
msgattrib_OBJECTS = msgattrib.obj
msgcat_OBJECTS = msgcat.obj
msgcomm_OBJECTS = msgcomm.obj
@@ -269,6 +270,9 @@
format-php.obj : format-php.c
$(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c format-php.c
+format-ocaml.obj : format-ocaml.c
+ $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c format-ocaml.c
+
!if !$(DLL)
gettextsrc.lib : $(OBJECTS)
@@ -360,6 +364,9 @@
x-php.obj : x-php.c
$(CC) $(INCLUDES) $(CFLAGS) -c x-php.c
+x-ocaml.obj : x-ocaml.c
+ $(CC) $(INCLUDES) $(CFLAGS) -c x-ocaml.c
+
x-rst.obj : x-rst.c
$(CC) $(INCLUDES) $(CFLAGS) -c x-rst.c
diff -Nurd gettext-0.12.1/gettext-tools/src/Makefile.vms gettext-0.12.1.ocaml/gettext-tools/src/Makefile.vms
--- gettext-0.12.1/gettext-tools/src/Makefile.vms 2003-04-29 12:00:16.000000000 +0200
+++ gettext-0.12.1.ocaml/gettext-tools/src/Makefile.vms 2003-07-16 22:07:34.000000000 +0200
@@ -85,13 +85,14 @@
format-pascal.obj, \
format-ycp.obj, \
format-tcl.obj, \
- format-php.obj
+ format-php.obj \
+ format-ocaml.obj
msgcmp_OBJECTS = msgcmp.obj
msgfmt_OBJECTS = msgfmt.obj, write-mo.obj, write-java.obj, write-tcl.obj, plural-eval.obj
msgmerge_OBJECTS = msgmerge.obj
msgunfmt_OBJECTS = msgunfmt.obj, read-mo.obj, read-java.obj, read-tcl.obj
-xgettext_OBJECTS = xgettext.obj, x-c.obj, x-po.obj, x-python.obj, x-lisp.obj, x-elisp.obj, x-librep.obj, x-smalltalk.obj, x-java.obj, x-awk.obj, x-ycp.obj, x-tcl.obj, x-php.obj, x-rst.obj, x-glade.obj
+xgettext_OBJECTS = xgettext.obj, x-c.obj, x-po.obj, x-python.obj, x-lisp.obj, x-elisp.obj, x-librep.obj, x-smalltalk.obj, x-java.obj, x-awk.obj, x-ycp.obj, x-tcl.obj, x-php.obj, x-rst.obj, x-glade.obj x-ocaml.obj
msgattrib_OBJECTS = msgattrib.obj
msgcat_OBJECTS = msgcat.obj
msgcomm_OBJECTS = msgcomm.obj
@@ -213,6 +214,9 @@
format-php.obj : format-php.c
$(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) format-php.c
+format-ocaml.obj : format-ocaml.c
+ $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) format-ocaml.c
+
gettextsrc.olb : $(OBJECTS)
$(AR) $(AR_FLAGS) gettextsrc.olb $(OBJECTS)
@@ -290,6 +294,9 @@
x-php.obj : x-php.c
$(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) x-php.c
+x-ocaml.obj : x-ocaml.c
+ $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) x-ocaml.c
+
x-rst.obj : x-rst.c
$(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) x-rst.c
diff -Nurd gettext-0.12.1/gettext-tools/src/format-ocaml.c gettext-0.12.1.ocaml/gettext-tools/src/format-ocaml.c
--- gettext-0.12.1/gettext-tools/src/format-ocaml.c 1970-01-01 01:00:00.000000000 +0100
+++ gettext-0.12.1.ocaml/gettext-tools/src/format-ocaml.c 2003-07-16 22:19:35.000000000 +0200
@@ -0,0 +1,108 @@
+/* Ocaml format strings.
+ Copyright (C) 2001-2003 Free Software Foundation, Inc.
+ Written by Sylvain LE GALL <sylvain.le-gall@polytechnique.org>, 2003.
+
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "format.h"
+#include "xmalloc.h"
+#include "xerror.h"
+#include "format-invalid.h"
+#include "error.h"
+#include "progname.h"
+#include "gettext.h"
+
+#define _(str) gettext (str)
+
+/* Ocaml Printf format string
+ Unfortunately, there is no way to explicitely use args in string from
+ ocaml. One way is to use Printf.* but, it needs a plain string ( and not
+ the return of a function ).
+
+ Still working on it
+*/
+
+struct spec
+{
+ int directives;
+};
+
+static void *
+format_parse (const char *format, char **invalid_reason)
+{
+ struct spec spec;
+ struct spec *result;
+
+ spec.directives = 0;
+
+ result = (struct spec *) xmalloc (sizeof (struct spec) );
+ *result = spec;
+ return result;
+}
+
+static void
+format_free (void *descr)
+{
+ struct spec *spec = (struct spec *) descr;
+
+ free (spec);
+}
+
+static int
+format_get_number_of_directives (void *descr)
+{
+ struct spec *spec = (struct spec *) descr;
+
+ return spec->directives;
+}
+
+static bool
+format_check (const lex_pos_ty *pos, void *msgid_descr, void *msgstr_descr,
+ bool equality, bool noisy, const char *pretty_msgstr)
+{
+ struct spec *spec1 = (struct spec *) msgid_descr;
+ struct spec *spec2 = (struct spec *) msgstr_descr;
+ bool err = false;
+ unsigned int i;
+
+ // We have always 0 directives
+ if ( equality )
+ {
+ err = true;
+ }
+ else
+ {
+ err = false;
+ };
+
+ return err;
+}
+
+
+struct formatstring_parser formatstring_ocaml =
+{
+ format_parse,
+ format_free,
+ format_get_number_of_directives,
+ format_check
+};
+
diff -Nurd gettext-0.12.1/gettext-tools/src/format.c gettext-0.12.1.ocaml/gettext-tools/src/format.c
--- gettext-0.12.1/gettext-tools/src/format.c 2002-08-19 13:00:09.000000000 +0200
+++ gettext-0.12.1.ocaml/gettext-tools/src/format.c 2003-07-16 22:16:32.000000000 +0200
@@ -37,5 +37,6 @@
/* format_pascal */ &formatstring_pascal,
/* format_ycp */ &formatstring_ycp,
/* format_tcl */ &formatstring_tcl,
- /* format_php */ &formatstring_php
+ /* format_php */ &formatstring_php,
+ /* format_ocaml */ &formatstring_ocaml
};
diff -Nurd gettext-0.12.1/gettext-tools/src/format.h gettext-0.12.1.ocaml/gettext-tools/src/format.h
--- gettext-0.12.1/gettext-tools/src/format.h 2003-02-24 11:50:20.000000000 +0100
+++ gettext-0.12.1.ocaml/gettext-tools/src/format.h 2003-07-03 18:47:27.000000000 +0200
@@ -67,6 +67,7 @@
extern struct formatstring_parser formatstring_ycp;
extern struct formatstring_parser formatstring_tcl;
extern struct formatstring_parser formatstring_php;
+extern struct formatstring_parser formatstring_ocaml;
/* Table of all format string parsers. */
extern struct formatstring_parser *formatstring_parsers[NFORMATS];
diff -Nurd gettext-0.12.1/gettext-tools/src/message.c gettext-0.12.1.ocaml/gettext-tools/src/message.c
--- gettext-0.12.1/gettext-tools/src/message.c 2003-04-29 12:04:04.000000000 +0200
+++ gettext-0.12.1.ocaml/gettext-tools/src/message.c 2003-07-16 22:09:07.000000000 +0200
@@ -45,7 +45,8 @@
/* format_pascal */ "object-pascal",
/* format_ycp */ "ycp",
/* format_tcl */ "tcl",
- /* format_php */ "php"
+ /* format_php */ "php",
+ /* format_ocaml */ "ocaml"
};
const char *const format_language_pretty[NFORMATS] =
@@ -61,7 +62,8 @@
/* format_pascal */ "Object Pascal",
/* format_ycp */ "YCP",
/* format_tcl */ "Tcl",
- /* format_php */ "PHP"
+ /* format_php */ "PHP",
+ /* format_ocaml */ "Objective Caml"
};
diff -Nurd gettext-0.12.1/gettext-tools/src/message.h gettext-0.12.1.ocaml/gettext-tools/src/message.h
--- gettext-0.12.1/gettext-tools/src/message.h 2003-04-29 12:04:04.000000000 +0200
+++ gettext-0.12.1.ocaml/gettext-tools/src/message.h 2003-07-03 18:48:21.000000000 +0200
@@ -45,9 +45,10 @@
format_pascal,
format_ycp,
format_tcl,
- format_php
+ format_php,
+ format_ocaml
};
-#define NFORMATS 12 /* Number of format_type enum values. */
+#define NFORMATS 13 /* Number of format_type enum values. */
extern const char *const format_language[NFORMATS];
extern const char *const format_language_pretty[NFORMATS];
diff -Nurd gettext-0.12.1/gettext-tools/src/test.c gettext-0.12.1.ocaml/gettext-tools/src/test.c
--- gettext-0.12.1/gettext-tools/src/test.c 1970-01-01 01:00:00.000000000 +0100
+++ gettext-0.12.1.ocaml/gettext-tools/src/test.c 2003-07-17 00:02:24.000000000 +0200
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "xsetenv.h"
+#define _(string) gettext (string)
+
+int main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int n = atoi (argv[2]);
+
+ xsetenv ("LC_ALL", argv[1], 1);
+ if (setlocale (LC_ALL, "") == NULL)
+ {
+ fprintf (stderr, "Couldn't set locale.\n");
+ exit (77);
+ }
+
+ textdomain ("prog");
+ bindtextdomain ("prog", ".");
+
+ gettext("Bonjour");
+
+ exit (0);
+}
diff -Nurd gettext-0.12.1/gettext-tools/src/x-ocaml.c gettext-0.12.1.ocaml/gettext-tools/src/x-ocaml.c
--- gettext-0.12.1/gettext-tools/src/x-ocaml.c 1970-01-01 01:00:00.000000000 +0100
+++ gettext-0.12.1.ocaml/gettext-tools/src/x-ocaml.c 2003-07-17 23:37:00.000000000 +0200
@@ -0,0 +1,873 @@
+/* xgettext Ocaml backend.
+ Copyright (C) 2003, Sylvain LE GALL <sylvain.le-gall@polytechnique.org>
+
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "message.h"
+#include "x-ocaml.h"
+#include "xgettext.h"
+#include "error.h"
+#include "progname.h"
+#include "xmalloc.h"
+#include "exit.h"
+#include "hash.h"
+#include "gettext.h"
+
+#define _(s) gettext(s)
+
+
+/* Ocaml defines string format in
+http://localhost/cgi-bin/dwww?type=file&location=/usr/share/doc/ocaml/docs/ocaml.html/manual009.html
+
+ 1. Use the text at the adress given to lexify token from input stream
+
+ 2. When a keyword is found find the attached string ( if any )
+
+ This lexer implements the above, and presents the scanner (in xgettext.c)
+ with a stream of Ocaml tokens. The comments are accumulated in a buffer,
+ and given to xgettext when asked for. */
+
+enum xgettext_token_type_ty
+{
+ xgettext_token_type_string_literal,
+ xgettext_token_type_comment,
+ xgettext_token_type_symbol,
+ xgettext_token_type_keyword,
+ xgettext_token_type_beg_parent,
+ xgettext_token_type_end_parent,
+ xgettext_token_type_eof
+};
+
+typedef enum xgettext_token_type_ty xgettext_token_type_ty;
+
+typedef struct xgettext_token_ty xgettext_token_ty;
+struct xgettext_token_ty
+{
+ xgettext_token_type_ty type;
+
+ /* These fields are used only for xgettext_token_type_keyword. */
+ int argnum1;
+ int argnum2;
+
+ /* This field is used only for xgettext_token_type_string_literal. */
+ char *string;
+
+ /* These fields are only for
+ xgettext_token_type_keyword,
+ xgettext_token_type_string_literal. */
+ lex_pos_ty pos;
+};
+
+
+/* ========================= Lexer customization. ========================= */
+
+/* ====================== Keyword set customization. ====================== */
+
+/* If true extract all strings. */
+static bool extract_all = false;
+
+static hash_table keywords;
+static bool default_keywords = true;
+
+
+void
+x_ocaml_extract_all ()
+{
+ extract_all = true;
+}
+
+
+void
+x_ocaml_keyword (const char *name)
+{
+ if (name == NULL)
+ default_keywords = false;
+ else
+ {
+ const char *end;
+ int argnum1;
+ int argnum2;
+ const char *colon;
+
+ if (keywords.table == NULL)
+ init_hash (&keywords, 100);
+
+ split_keywordspec (name, &end, &argnum1, &argnum2);
+
+ /* The characters between name and end should form a valid Ocaml identifier.
+ A colon means an invalid parse in split_keywordspec(). */
+ colon = strchr (name, ':');
+ if (colon == NULL || colon >= end)
+ {
+ if (argnum1 == 0)
+ argnum1 = 1;
+ insert_entry (&keywords, name, end - name,
+ (void *) (long) (argnum1 + (argnum2 << 10)));
+ }
+ }
+}
+
+bool
+x_ocaml_any_keywords ()
+{
+ return (keywords.filled > 0) || default_keywords;
+}
+
+/* Finish initializing the keywords hash table.
+ Called after argument processing, before each file is processed. */
+static void
+init_keywords ()
+{
+ if (default_keywords)
+ {
+ x_ocaml_keyword ("gettext");
+ x_ocaml_keyword ("Camlgettext.gettext");
+ x_ocaml_keyword ("dgettext:2");
+ x_ocaml_keyword ("Camlgettext.dgettext:2");
+ x_ocaml_keyword ("dcgettext:2");
+ x_ocaml_keyword ("Camlgettext.dcgettext:2");
+ x_ocaml_keyword ("ngettext:1,2");
+ x_ocaml_keyword ("Camlgettext.ngettext:1,2");
+ x_ocaml_keyword ("dngettext:2,3");
+ x_ocaml_keyword ("Camlgettext.dngettext:2,3");
+ x_ocaml_keyword ("dcngettext:2,3");
+ x_ocaml_keyword ("Camlgettext.dcngettext:2,3");
+ x_ocaml_keyword ("gettext_noop:2,3");
+ x_ocaml_keyword ("Camlgettext.gettext_noop:2,3");
+ default_keywords = false;
+ }
+}
+
+
+/* ================== Reading of characters and tokens. =================== */
+
+/* Real filename, used in error messages about the input file. */
+static const char *real_file_name;
+
+/* Logical filename and line number, used to label the extracted messages. */
+static char *logical_file_name;
+static int line_number;
+
+/* The input file stream. */
+static FILE *fp;
+
+
+/* Maximum used guaranteed to be < 4. */
+static unsigned char phase1_pushback[4];
+static int phase1_pushback_length;
+static bool last_was_eof = false;
+
+static int
+phase1_getc ()
+{
+ int c;
+
+ if (phase1_pushback_length)
+ {
+ c = phase1_pushback[--phase1_pushback_length];
+ if ( c == '\n' )
+ ++line_number;
+
+ if ( c == EOF )
+ last_was_eof = true;
+
+ return c;
+ }
+ for (;;)
+ {
+ c = getc (fp);
+ switch (c)
+ {
+ case EOF:
+ if (ferror (fp))
+ {
+ error (EXIT_FAILURE, errno,
+ _("error while reading \"%s\""), real_file_name);
+ };
+
+ if ( last_was_eof )
+ {
+ /* We ask two time for eof... We are looping */
+ error (EXIT_FAILURE, errno,
+ _("try to extract repeatedly eof while reading \"%s\""), real_file_name);
+ };
+
+ last_was_eof = true;
+ return EOF;
+
+ case '\n':
+ ++line_number;
+ last_was_eof = false;
+ return '\n';
+
+ default:
+ last_was_eof = false;
+ return c;
+ }
+ }
+}
+
+
+static void
+phase1_ungetc (int c)
+{
+ switch (c)
+ {
+ case EOF:
+ break;
+
+ case '\n':
+ --line_number;
+ /* FALLTHROUGH */
+
+ default:
+ phase1_pushback[phase1_pushback_length++] = c;
+ break;
+ }
+}
+
+
+/*
+ Taken from the lexer.mll find at the adress given
+ */
+
+static void
+eof_error ( const char * where, int c )
+{
+ if ( c == EOF )
+ {
+ /* Error : we reach the end of the stream */
+
+ error_with_progname = false;
+ error (0, 0, _("%s:%d: warning: unterminated %s, we reach EOF"),
+ logical_file_name, line_number - 1, where);
+ error_with_progname = true;
+ }
+
+}
+
+#define IS_BLANKS(c) (c == ' ' || c == '\013' || c == '\t' || c == '\012' || c == '\010')
+
+#define IS_BACKSLASHES_ESCAPES(c) (( c == '\\' ) \
+ || (c == '"') \
+ || (c == '\'') \
+ || (c == 'n') \
+ || (c == 't') \
+ || (c == 'b') \
+ || (c == 'r'))
+
+#define VAL_BACKSLASHES_ESCAPES(c) \
+ ( c == 'n' ? '\n' : \
+ ( c == 't' ? '\t' : \
+ ( c == 'b' ? '\b' : \
+ ( c == 'r' ? '\r' : \
+ c \
+ )\
+ )\
+ )\
+ )\
+
+#define LINE_SPLIT 1000
+
+static int
+get_regular_char ( bool *is_backslashed )
+{
+ int c, i, res;
+
+ *is_backslashed = false;
+ c = phase1_getc();
+
+ if ( c == '\\' )
+ {
+ c = phase1_getc();
+
+ if ( IS_BACKSLASHES_ESCAPES(c) )
+ {
+ *is_backslashed = true;
+ res = VAL_BACKSLASHES_ESCAPES(c);
+ }
+ else if ( '0' <= c && c <= '9' )
+ {
+ *is_backslashed = true;
+ for ( i = 0, res = 0 ; i < 3 ; i ++ )
+ {
+ switch (c)
+ {
+ case '0' : case '1' : case '2' : case '3' : case '4' :
+ case '5' : case '6' : case '7' : case '8' : case '9' :
+ break;
+ default:
+ /* Error non number in the numeric definition*/
+ error_with_progname = false;
+ error (0, 0, _(
+ "%s:%d: warning: numeric character constant contains non numeric char (%c)"),
+ logical_file_name, line_number - 1, c);
+ error_with_progname = true;
+ phase1_ungetc(c);
+ c = '0';
+ break;
+ };
+ res = res * 10 + (c - '0');
+ c = phase1_getc();
+ };
+
+ if ( res > 255 )
+ {
+ /* Error number defined is too big */
+ error_with_progname = false;
+ error (0, 0, _("%s:%d: warning: character constant too high"),
+ logical_file_name, line_number - 1);
+ error_with_progname = true;
+ res = 255;
+ };
+ }
+ else
+ {
+ /* We have a backslash but nothing can be backslashed */
+ *is_backslashed = false;
+ phase1_ungetc(c);
+ res = '\\';
+ };
+ }
+ else
+ {
+ *is_backslashed = false;
+ res = c;
+ };
+
+ return res;
+}
+
+static void
+extract_char ( xgettext_token_ty *tp )
+{
+ int c, res;
+ bool is_backslashed;
+ char buffer[2];
+
+
+ res = get_regular_char(&is_backslashed);
+ c = phase1_getc();
+
+ /* We verify that we reach the end of the char */
+
+ if ( c != '\'' )
+ {
+ /* We have only the 'x which is a generic type */
+ tp->type = xgettext_token_type_symbol;
+ tp->string = NULL;
+ tp->argnum1 = 0;
+ tp->argnum2 = 0;
+ tp->pos.file_name = logical_file_name;
+ tp->pos.line_number = line_number;
+
+ phase1_ungetc(c);
+ }
+ else
+ {
+ buffer[0]=res;
+ buffer[1]='\0';
+ tp->type = xgettext_token_type_string_literal;
+ tp->string = xstrdup(buffer);
+ tp->argnum1 = 0;
+ tp->argnum2 = 0;
+ tp->pos.file_name = logical_file_name;
+ tp->pos.line_number = line_number;
+ };
+
+}
+
+static void
+extract_string ( xgettext_token_ty *tp )
+{
+ int bufmax = 0;
+ int bufpos = 0;
+ char *buffer = NULL;
+ int c, res;
+ bool is_backslashed;
+
+ buffer = xrealloc (buffer, bufmax);
+
+ c = get_regular_char(&is_backslashed);
+
+ while ( !(c == '"' && !is_backslashed ) && c != EOF )
+ {
+
+ /* Possible start of a \\ (CR|LF|CRLF...) (' ' '\t')* ( line split ) ? */
+ if ( c == '\\' && !is_backslashed )
+ {
+
+ c = phase1_getc();
+
+ while ( IS_BLANKS(c) )
+ {
+ c = phase1_getc();
+ };
+
+ phase1_ungetc(c);
+ }
+ else
+ {
+ if (bufpos >= bufmax)
+ {
+ bufmax += 100;
+ buffer = xrealloc (buffer, bufmax);
+ }
+ buffer[bufpos++] = c;
+ }
+
+ c = get_regular_char(&is_backslashed);
+ };
+
+ buffer[bufpos] = 0;
+
+ tp->type = xgettext_token_type_string_literal;
+ tp->string = xstrdup (buffer);
+ tp->argnum1 = 0;
+ tp->argnum2 = 0;
+ tp->pos.file_name = logical_file_name;
+ tp->pos.line_number = line_number;
+}
+
+static void
+extract_comment ( xgettext_token_ty *tp )
+{
+ int bufmax = 0;
+ int bufpos = 0;
+ char *buffer = NULL;
+ /* If we are here, it means we have gone through a leading (* */
+ int comment_depth = 1;
+ int c1, c2;
+
+ buffer = xrealloc (buffer, bufmax);
+
+ c2 = phase1_getc();
+
+ while ( comment_depth != 0 )
+ {
+ c1 = c2;
+ c2 = phase1_getc();
+ /* Is it a *) ? */
+ if ( c1 == '*' && c2 == ')' )
+ {
+ comment_depth--;
+ }
+ else if ( c1 == '(' && c2 == '*' )
+ {
+ comment_depth++;
+ };
+
+ if (bufpos >= bufmax)
+ {
+ bufmax += 100;
+ buffer = xrealloc (buffer, bufmax);
+ };
+
+ /* We transform a multiline comment into a single line one */
+ if ( c1 != '\r' && c1 != '\n' )
+ {
+ buffer[bufpos++] = c1;
+ };
+ };
+
+ bufpos--; /* We remove the trailing * */
+ buffer[bufpos] = 0;
+ tp->type = xgettext_token_type_comment;
+ tp->string = xstrdup (buffer);
+ tp->argnum1 = 0;
+ tp->argnum2 = 0;
+ tp->pos.file_name = logical_file_name;
+ tp->pos.line_number = line_number;
+}
+
+#define IN_RANGE(c, a, b) ( a <= c && c <= b )
+#define SKIP(c, test) \
+ c = phase1_getc();\
+ while ( test ) { c = phase1_getc() ; }; \
+ phase1_ungetc(c)
+
+static void
+extract_numeric ( xgettext_token_ty *tp )
+{
+ int c1, c2, c;
+ /* We don't care about the numeric value... We just skip it */
+
+ c1 = phase1_getc();
+ c2 = phase1_getc();
+
+ if ( c1 == '-' )
+ {
+ c1 = c2;
+ c2 = phase1_getc();
+ };
+
+ if ( c1 == '0' && (c2 == 'x' || c2 == 'X'))
+ {
+ SKIP(c, IN_RANGE(c, '0', '7')
+ || IN_RANGE(c, 'A', 'F')
+ || IN_RANGE(c, 'a', 'f'));
+ }
+ else if ( c1 == '0' && (c2 == 'o' || c2 == 'O'))
+ {
+ SKIP(c, IN_RANGE(c, '0', '7'));
+ }
+ else if ( c1 == '0' && (c2 == 'b' || c2 == 'B'))
+ {
+ SKIP(c, IN_RANGE(c, '0', '1'));
+ }
+ else
+ {
+ phase1_ungetc(c2);
+ phase1_ungetc(c1);
+
+ SKIP(c, IN_RANGE(c, '0', '9'));
+ SKIP(c, (c == '.'));
+ SKIP(c, IN_RANGE(c, '0', '9'));
+ SKIP(c, (c == 'e' || c == 'E' || c == '+' || c == '-' ) );
+ SKIP(c, IN_RANGE(c, '0', '9'));
+ }
+
+ tp->type = xgettext_token_type_symbol;
+ tp->string = NULL;
+ tp->argnum1 = 0;
+ tp->argnum2 = 0;
+ tp->pos.file_name = logical_file_name;
+ tp->pos.line_number = line_number;
+}
+
+
+static void
+extract_ident ( xgettext_token_ty *tp )
+{
+ void *keyword_value;
+ int bufmax = 0;
+ int bufpos = 0;
+ char *buffer = NULL;
+ int c;
+
+ buffer = xrealloc (buffer, bufmax);
+
+ c = phase1_getc();
+
+ if (bufpos >= bufmax)
+ {
+ bufmax += 100;
+ buffer = xrealloc (buffer, bufmax);
+ };
+
+ buffer[bufpos++] = c;
+
+ c = phase1_getc();
+
+ while ( c != '(' && c != ')' && c !='"' && c!='\'' && c != EOF && !IS_BLANKS(c) )
+ {
+ if (bufpos >= bufmax)
+ {
+ bufmax += 100;
+ buffer = xrealloc (buffer, bufmax);
+ };
+
+ buffer[bufpos++] = c;
+
+ c = phase1_getc();
+ }
+
+ phase1_ungetc(c);
+
+ buffer[bufpos] = 0;
+
+ if (find_entry (&keywords, buffer, strlen(buffer), &keyword_value) == 0)
+ {
+
+ tp->type = xgettext_token_type_keyword;
+ tp->string = NULL;
+ tp->argnum1 = (int) (long) keyword_value & ((1 << 10) - 1);
+ tp->argnum2 = (int) (long) keyword_value >> 10;
+ tp->pos.file_name = logical_file_name;
+ tp->pos.line_number = line_number;
+ }
+ else
+ {
+ tp->type = xgettext_token_type_symbol;
+ tp->string = NULL;
+ tp->argnum1 = 0;
+ tp->argnum2 = 0;
+ tp->pos.file_name = logical_file_name;
+ tp->pos.line_number = line_number;
+ }
+}
+
+static void
+ocaml_lex ( xgettext_token_ty *tp )
+{
+ int c;
+
+ /* Eat white space and all this kind of stuff */
+
+ c = phase1_getc();
+
+ while ( IS_BLANKS(c) )
+ {
+ c = phase1_getc();
+ }
+
+
+ switch (c)
+ {
+ case '(' :
+ c = phase1_getc();
+ if ( c == '*' )
+ {
+ return extract_comment(tp);
+ }
+ else
+ {
+ phase1_ungetc(c);
+ tp->type = xgettext_token_type_beg_parent;
+ tp->string = NULL;
+ tp->argnum1 = 0;
+ tp->argnum2 = 0;
+ tp->pos.file_name = logical_file_name;
+ tp->pos.line_number = line_number;
+ }
+ break;
+
+ case ')' :
+ tp->type = xgettext_token_type_end_parent;
+ tp->string = NULL;
+ tp->argnum1 = 0;
+ tp->argnum2 = 0;
+ tp->pos.file_name = logical_file_name;
+ tp->pos.line_number = line_number;
+ break;
+
+ case '0' : case '1' : case '2' : case '3' : case '4' :
+ case '5' : case '6' : case '7' : case '8' : case '9' :
+ case '-' : case '.' :
+ phase1_ungetc(c);
+ return extract_numeric(tp);
+ break;
+
+ case '\'' :
+ return extract_char(tp);
+ break;
+
+ case '"' :
+ return extract_string(tp);
+ break;
+
+ case EOF :
+ tp->type = xgettext_token_type_eof;
+ tp->string = NULL;
+ tp->argnum1 = 0;
+ tp->argnum2 = 0;
+ tp->pos.file_name = logical_file_name;
+ tp->pos.line_number = line_number;
+ break;
+
+ default :
+ phase1_ungetc(c);
+ return extract_ident(tp);
+ break;
+ }
+}
+
+
+/* ========================= Extracting strings. ========================== */
+
+/* The file is broken into tokens. Scan the token stream, looking for
+ a keyword, followed by a left paren, followed by a string. When we
+ see this sequence, we have something to remember. We assume we are
+ looking at a valid C or C++ program, and leave the complaints about
+ the grammar to the compiler.
+
+ Normal handling: Look for
+ keyword ( ... msgid ... )
+ Plural handling: Look for
+ keyword ( ... msgid ... msgid_plural ... )
+
+ We use recursion because the arguments before msgid or between msgid
+ and msgid_plural can contain subexpressions of the same form. */
+
+
+static bool
+ocaml_parse ( message_list_ty *mlp )
+{
+ xgettext_token_ty token;
+ message_ty *plural_mp = NULL;
+ int next_string = -1;
+ int next_plural = -1;
+
+ for ( ; ; )
+ {
+ ocaml_lex(&token);
+
+ next_string--;
+ if ( next_string <= -1 )
+ {
+ next_string = -1;
+ }
+
+ next_plural--;
+ if ( next_plural <= -1 )
+ {
+ next_plural = -1;
+ }
+
+ if ( !extract_all )
+ {
+ switch ( token.type )
+ {
+ case xgettext_token_type_string_literal :
+ if ( next_string == 0 && next_plural > 0 )
+ {
+ plural_mp=remember_a_message(mlp, token.string, &token.pos);
+ }
+ else if ( next_string == 0 && next_plural < 0 )
+ {
+ remember_a_message(mlp, token.string, &token.pos);
+ plural_mp=NULL;
+ }
+ else if ( next_string < 0 && next_plural == 0 && plural_mp != NULL )
+ {
+ remember_a_message_plural(plural_mp, token.string, &token.pos);
+ plural_mp = NULL;
+ }
+ else if ( next_string == 0 && next_plural == 0 )
+ {
+ /* Error : we string && plural at the same time */
+ error_with_progname = false;
+ error (0, 0, _("%s:%d: warning: plural and singular at the same position ( skipping )"),
+ logical_file_name, line_number - 1);
+ error_with_progname = true;
+
+ next_string = -1;
+ next_plural = -1;
+ free(token.string);
+ }
+ else if ( next_string > 0 && next_plural == 0 )
+ {
+
+ /* Error : plural before singular*/
+ error_with_progname = false;
+ error (0, 0, _("%s:%d: warning: plural before singular ( skipping )"),
+ logical_file_name, line_number - 1);
+ error_with_progname = true;
+
+ next_string = -1;
+ next_plural = -1;
+ free(token.string);
+
+ }
+ else if ( next_string < 0 && next_plural == 0 && plural_mp == NULL )
+ {
+ /* Error : singular never found*/
+ error_with_progname = false;
+ error (0, 0, _("%s:%d: warning: singular form never found ( skipping )"),
+ logical_file_name, line_number - 1);
+ error_with_progname = true;
+
+ next_string = -1;
+ next_plural = -1;
+ free(token.string);
+ }
+ else
+ {
+ free(token.string);
+ }
+ break;
+ case xgettext_token_type_comment :
+ xgettext_comment_add(token.string);
+ free(token.string);
+ break;
+ case xgettext_token_type_symbol :
+ xgettext_comment_reset();
+ break;
+ case xgettext_token_type_keyword :
+ next_string = token.argnum1;
+ next_plural = token.argnum2;
+ xgettext_comment_reset();
+ break;
+ case xgettext_token_type_beg_parent :
+ xgettext_comment_reset();
+ if ( !ocaml_parse(mlp) )
+ {
+ /* Error : reach the end parenthized not balanced*/
+ error_with_progname = false;
+ error (0, 0, _("%s:%d: warning: some parenthizes are not matched"),
+ logical_file_name, line_number - 1);
+ error_with_progname = true;
+ };
+ break;
+ case xgettext_token_type_end_parent :
+ xgettext_comment_reset();
+ return true;
+ break;
+ case xgettext_token_type_eof :
+ xgettext_comment_reset();
+ return false;
+ break;
+ default :
+ abort();
+
+ }
+ }
+ else if ( token.type == xgettext_token_type_string_literal )
+ {
+ if ( strlen(token.string) > 0 )
+ remember_a_message(mlp, token.string, &token.pos);
+ }
+ else if ( token.type == xgettext_token_type_eof )
+ {
+ return false;
+ }
+ }
+}
+
+
+void
+extract_ocaml (FILE *f,
+ const char *real_filename, const char *logical_filename,
+ msgdomain_list_ty *mdlp)
+{
+ message_list_ty *mlp = mdlp->item[0]->messages;
+
+ fp = f;
+ real_file_name = real_filename;
+ logical_file_name = xstrdup (logical_filename);
+ line_number = 1;
+
+ init_keywords ();
+
+ /* Eat token until eof */
+ ocaml_parse(mlp);
+
+ /* Close scanner. */
+ fp = NULL;
+ real_file_name = NULL;
+ logical_file_name = NULL;
+ line_number = 0;
+}
+
diff -Nurd gettext-0.12.1/gettext-tools/src/x-ocaml.h gettext-0.12.1.ocaml/gettext-tools/src/x-ocaml.h
--- gettext-0.12.1/gettext-tools/src/x-ocaml.h 1970-01-01 01:00:00.000000000 +0100
+++ gettext-0.12.1.ocaml/gettext-tools/src/x-ocaml.h 2003-07-16 22:45:26.000000000 +0200
@@ -0,0 +1,35 @@
+/* xgettext Ocaml backend.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ Written by Sylvain LE GALL <sylvain.le-gall@polytechnique.org>, 2003.
+
+ 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. */
+
+
+#define EXTENSIONS_OCAML \
+ { "ml", "Ocaml" }, \
+
+#define SCANNERS_OCAML \
+ { "Ocaml", extract_ocaml, &formatstring_ocaml }, \
+
+/* Scan an Ocaml file and add its translatable strings to mdlp. */
+extern void extract_ocaml (FILE *fp, const char *real_filename,
+ const char *logical_filename,
+ msgdomain_list_ty *mdlp);
+
+
+/* Handling of options specific to this language. */
+
+extern void x_ocaml_extract_all (void);
+extern void x_ocaml_keyword (const char *name);
diff -Nurd gettext-0.12.1/gettext-tools/src/xgettext.c gettext-0.12.1.ocaml/gettext-tools/src/xgettext.c
--- gettext-0.12.1/gettext-tools/src/xgettext.c 2003-05-21 12:56:46.000000000 +0200
+++ gettext-0.12.1.ocaml/gettext-tools/src/xgettext.c 2003-07-16 22:44:07.000000000 +0200
@@ -75,6 +75,7 @@
#include "x-ycp.h"
#include "x-tcl.h"
#include "x-php.h"
+#include "x-ocaml.h"
#include "x-rst.h"
#include "x-glade.h"
@@ -259,6 +260,7 @@
x_awk_extract_all ();
x_tcl_extract_all ();
x_php_extract_all ();
+ x_ocaml_extract_all ();
x_glade_extract_all ();
break;
case 'c':
@@ -318,6 +320,7 @@
x_awk_keyword (optarg);
x_tcl_keyword (optarg);
x_php_keyword (optarg);
+ x_ocaml_keyword (optarg);
x_glade_keyword (optarg);
}
break;
@@ -654,7 +657,7 @@
-L, --language=NAME recognise the specified language\n\
(C, C++, ObjectiveC, PO, Python, Lisp,\n\
EmacsLisp, librep, Smalltalk, Java,\n\
- JavaProperties, awk, YCP, Tcl, PHP, RST, Glade)\n"));
+ JavaProperties, awk, YCP, Tcl, PHP, RST, Glade, Ocaml)\n"));
printf (_("\
-C, --c++ shorthand for --language=C++\n"));
printf (_("\
@@ -1461,6 +1464,7 @@
SCANNERS_PHP
SCANNERS_RST
SCANNERS_GLADE
+ SCANNERS_OCAML
/* Here will follow more languages and their scanners: perl, etc...
Make sure new scanners honor the --exclude-file option. */
};
@@ -1509,6 +1513,7 @@
EXTENSIONS_PHP
EXTENSIONS_RST
EXTENSIONS_GLADE
+ EXTENSIONS_OCAML
/* Here will follow more file extensions: sh, pl ... */
};