diff --git a/src/compiler/GF/Command/Commands.hs b/src/compiler/GF/Command/Commands.hs index d000b35b0..9ea5cb6e0 100644 --- a/src/compiler/GF/Command/Commands.hs +++ b/src/compiler/GF/Command/Commands.hs @@ -847,7 +847,7 @@ pgfCommands = Map.fromList [ prGrammar pgf opts | isOpt "pgf" opts = do let outfile = valStrOpts "file" (abstractName pgf ++ ".pgf") opts - restricted $ writePGF outfile pgf + restricted $ writePGF outfile pgf (Just (map concreteName (optLangs pgf opts))) putStrLn $ "wrote file " ++ outfile return void | isOpt "cats" opts = return $ fromString $ unwords $ categories pgf diff --git a/src/compiler/GF/Compiler.hs b/src/compiler/GF/Compiler.hs index 92b207900..9e8b6cb07 100644 --- a/src/compiler/GF/Compiler.hs +++ b/src/compiler/GF/Compiler.hs @@ -180,7 +180,7 @@ writeGrammar :: Options -> PGF -> IOE () writeGrammar opts pgf = if fst (flag optLinkTargets opts) then do let outfile = outputPath opts (grammarName opts pgf <.> "pgf") - writing opts outfile (writePGF outfile pgf) + writing opts outfile (writePGF outfile pgf Nothing) else return () writeOutput :: Options -> FilePath-> String -> IOE () diff --git a/src/runtime/c/pgf/pgf.cxx b/src/runtime/c/pgf/pgf.cxx index f2230d3b9..95959b4d5 100644 --- a/src/runtime/c/pgf/pgf.cxx +++ b/src/runtime/c/pgf/pgf.cxx @@ -244,6 +244,7 @@ void pgf_merge_pgf(PgfDB *db, PgfRevision revision, PGF_API void pgf_write_pgf(const char* fpath, PgfDB *db, PgfRevision revision, + PgfText **langs, PgfExn* err) { FILE *out = NULL; @@ -258,7 +259,7 @@ void pgf_write_pgf(const char* fpath, DB_scope scope(db, READER_SCOPE); ref pgf = db->revision2pgf(revision); - PgfWriter wtr(out); + PgfWriter wtr(langs, out); wtr.write_pgf(pgf); } } PGF_API_END diff --git a/src/runtime/c/pgf/pgf.h b/src/runtime/c/pgf/pgf.h index 06776570c..56b5b3ed9 100644 --- a/src/runtime/c/pgf/pgf.h +++ b/src/runtime/c/pgf/pgf.h @@ -287,6 +287,7 @@ void pgf_merge_pgf(PgfDB *db, PgfRevision revision, PGF_API_DECL void pgf_write_pgf(const char* fpath, PgfDB *db, PgfRevision revision, + PgfText **langs, // null terminated list or null PgfExn* err); PGF_API_DECL diff --git a/src/runtime/c/pgf/writer.cxx b/src/runtime/c/pgf/writer.cxx index 8b20495e0..3ef32ec4d 100644 --- a/src/runtime/c/pgf/writer.cxx +++ b/src/runtime/c/pgf/writer.cxx @@ -2,9 +2,10 @@ #include "data.h" #include "writer.h" -PgfWriter::PgfWriter(FILE *out) +PgfWriter::PgfWriter(PgfText **langs, FILE *out) { this->out = out; + this->langs = langs; this->abstract = 0; } @@ -411,6 +412,22 @@ void PgfWriter::write_printname(ref printname) void PgfWriter::write_concrete(ref concr) { + if (langs != NULL) { + bool found = false; + PgfText** p = langs; + while (*p) { + if (textcmp(*p, &concr->name) == 0) { + found = true; + break; + } + p++; + } + + if (!found) { + return; + } + } + seq_ids.start(concr); write_name(&concr->name); @@ -431,5 +448,16 @@ void PgfWriter::write_pgf(ref pgf) write_namespace(pgf->gflags, &PgfWriter::write_flag); write_abstract(ref::from_ptr(&pgf->abstract)); - write_namespace(pgf->concretes, &PgfWriter::write_concrete); + + if (langs == NULL) + write_len(namespace_size(pgf->concretes)); + else { + size_t len = 0; + PgfText** p = langs; + while (*p) { + len++; p++; + } + write_len(len); + } + write_namespace_helper(pgf->concretes, &PgfWriter::write_concrete); } diff --git a/src/runtime/c/pgf/writer.h b/src/runtime/c/pgf/writer.h index ab7400ec8..c596b1fb5 100644 --- a/src/runtime/c/pgf/writer.h +++ b/src/runtime/c/pgf/writer.h @@ -4,7 +4,7 @@ class PGF_INTERNAL_DECL PgfWriter { public: - PgfWriter(FILE *out); + PgfWriter(PgfText **langs, FILE *out); void write_uint8(uint8_t b); void write_u16be(uint16_t u); @@ -66,6 +66,7 @@ private: void write_presult(ref> r) { write_presult(*r); }; FILE *out; + PgfText **langs; ref abstract; PgfPhrasetableIds seq_ids; diff --git a/src/runtime/haskell/PGF2.hsc b/src/runtime/haskell/PGF2.hsc index 5e5f21d48..982cc24ff 100644 --- a/src/runtime/haskell/PGF2.hsc +++ b/src/runtime/haskell/PGF2.hsc @@ -188,11 +188,15 @@ newNGF abs_name mb_fpath = fptr <- newForeignPtrEnv pgf_free_revision c_db c_revision return (PGF c_db fptr Map.empty) -writePGF :: FilePath -> PGF -> IO () -writePGF fpath p = +writePGF :: FilePath -> PGF -> Maybe [ConcName] -> IO () +writePGF fpath p mb_langs = withCString fpath $ \c_fpath -> withForeignPtr (a_revision p) $ \c_revision -> - withPgfExn "writePGF" (pgf_write_pgf c_fpath (a_db p) c_revision) + maybe (\f -> f nullPtr) (withLangs []) mb_langs $ \c_langs -> + withPgfExn "writePGF" (pgf_write_pgf c_fpath (a_db p) c_revision c_langs) + where + withLangs clangs [] f = withArray0 nullPtr (reverse clangs) f + withLangs clangs (lang:langs) f = withText lang $ \clang -> withLangs (clang:clangs) langs f showPGF :: PGF -> String showPGF p = diff --git a/src/runtime/haskell/PGF2/FFI.hsc b/src/runtime/haskell/PGF2/FFI.hsc index 07e3db8b2..74fb8ca91 100644 --- a/src/runtime/haskell/PGF2/FFI.hsc +++ b/src/runtime/haskell/PGF2/FFI.hsc @@ -78,7 +78,7 @@ foreign import ccall pgf_new_ngf :: Ptr PgfText -> CString -> Ptr (Ptr PGF) -> P foreign import ccall pgf_merge_pgf :: Ptr PgfDB -> Ptr PGF -> CString -> Ptr PgfExn -> IO () -foreign import ccall pgf_write_pgf :: CString -> Ptr PgfDB -> Ptr PGF -> Ptr PgfExn -> IO () +foreign import ccall pgf_write_pgf :: CString -> Ptr PgfDB -> Ptr PGF -> Ptr (Ptr PgfText) -> Ptr PgfExn -> IO () foreign import ccall "pgf_free_revision" pgf_free_revision_ :: Ptr PgfDB -> Ptr PGF -> IO () diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c index c5a06dffb..901105d31 100644 --- a/src/runtime/python/pypgf.c +++ b/src/runtime/python/pypgf.c @@ -517,18 +517,45 @@ PGF_dealloc(PGFObject *self) } static PyObject * -PGF_writePGF(PGFObject *self, PyObject *args) +PGF_writePGF(PGFObject *self, PyObject *args, PyObject *kwargs) { + char *kwds[] = {"","langs",NULL}; + const char *fpath; - if (!PyArg_ParseTuple(args, "s", &fpath)) + PyObject *py_langs = NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|O!", &kwds[0], &fpath, &PyList_Type, &py_langs)) return NULL; + PgfText **langs = NULL; + if (py_langs != NULL) { + size_t len = PyList_Size(py_langs); + langs = (PgfText **) alloca((len+1)*sizeof(PgfText*)); + for (size_t i = 0; i < len; i++) { + langs[i] = PyUnicode_AsPgfText(PyList_GetItem(py_langs,i)); + if (!langs[i]) { + while (i > 0) { + FreePgfText(langs[--i]); + } + return NULL; + } + } + langs[len] = NULL; + } + PgfExn err; - pgf_write_pgf(fpath, self->db, self->revision, &err); + pgf_write_pgf(fpath, self->db, self->revision, langs, &err); if (handleError(err) != PGF_EXN_NONE) { return NULL; } + if (langs != NULL) { + PgfText **p = langs; + while (*p) { + FreePgfText(*p); + p++; + } + } + Py_RETURN_NONE; } @@ -1152,7 +1179,7 @@ PGF_embed(PGFObject* self, PyObject *modname) #endif static PyMethodDef PGF_methods[] = { - {"writePGF", (PyCFunction)PGF_writePGF, METH_VARARGS, + {"writePGF", (PyCFunction)PGF_writePGF, METH_VARARGS | METH_KEYWORDS, "Writes to a PGF file"}, {"categoryContext", (PyCFunction)PGF_categoryContext, METH_VARARGS, "Returns the context for a given category"