Code

Pot and Dutch translation update
[inkscape.git] / src / main.cpp
1 #define __MAIN_C__
3 /** \file
4  * Inkscape - an ambitious vector drawing program
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   Frank Felfe <innerspace@iname.com>
9  *   Davide Puricelli <evo@debian.org>
10  *   Mitsuru Oka <oka326@parkcity.ne.jp>
11  *   Masatake YAMATO  <jet@gyve.org>
12  *   F.J.Franklin <F.J.Franklin@sheffield.ac.uk>
13  *   Michael Meeks <michael@helixcode.com>
14  *   Chema Celorio <chema@celorio.com>
15  *   Pawel Palucha
16  *   Bryce Harrington <bryce@bryceharrington.com>
17  * ... and various people who have worked with various projects
18  *
19  * Copyright (C) 1999-2004 authors
20  * Copyright (C) 2001-2002 Ximian, Inc.
21  *
22  * Released under GNU GPL, read the file 'COPYING' for more information
23  */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29 #include "path-prefix.h"
31 // This has to be included prior to anything that includes setjmp.h, it croaks otherwise
32 #include <png.h>
34 #include <gtk/gtkmessagedialog.h>
36 #ifdef HAVE_IEEEFP_H
37 #include <ieeefp.h>
38 #endif
39 #include <cstring>
40 #include <string>
41 #include <locale.h>
42 #include <stdlib.h>
44 #include <popt.h>
45 #ifndef POPT_TABLEEND
46 #define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
47 #endif /* Not def: POPT_TABLEEND */
49 #include <libxml/tree.h>
50 #include <glib.h>
51 #include <glib/gprintf.h>
52 #include <glib-object.h>
53 #include <gtk/gtk.h>
54 #include <gtk/gtkmain.h>
55 #include <gtk/gtksignal.h>
56 #include <gtk/gtkwindow.h>
57 #include <gtk/gtkbox.h>
59 #include "gc-core.h"
61 #ifdef AND
62 #undef AND
63 #endif
65 #include "macros.h"
66 #include "file.h"
67 #include "document.h"
68 #include "sp-object.h"
69 #include "interface.h"
70 #include "print.h"
71 #include "color.h"
72 #include "sp-item.h"
73 #include "sp-root.h"
74 #include "unit-constants.h"
76 #include "svg/svg.h"
77 #include "svg/svg-color.h"
78 #include "svg/stringstream.h"
80 #include "inkscape-private.h"
81 #include "inkscape-version.h"
83 #include "sp-namedview.h"
84 #include "sp-guide.h"
85 #include "sp-object-repr.h"
86 #include "xml/repr.h"
88 #include "io/sys.h"
90 #include "debug/logger.h"
91 #include "debug/log-display-config.h"
93 #include "helper/png-write.h"
94 #include "helper/geom.h"
96 #include <extension/extension.h>
97 #include <extension/system.h>
98 #include <extension/db.h>
99 #include <extension/output.h>
100 #include <extension/input.h>
102 #ifdef WIN32
103 #include "registrytool.h"
104 #include "extension/internal/win32.h"
105 using Inkscape::Extension::Internal::PrintWin32;
106 #endif // WIN32
108 #include "extension/init.h"
110 #include <glibmm/i18n.h>
111 #include <gtkmm/main.h>
113 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
114 #define bind_textdomain_codeset(p,c)
115 #endif
117 #include "main-cmdlineact.h"
118 #include "widgets/icon.h"
119 #include "ui/widget/panel.h"
121 #include <errno.h>
123 enum {
124     SP_ARG_NONE,
125     SP_ARG_NOGUI,
126     SP_ARG_GUI,
127     SP_ARG_FILE,
128     SP_ARG_PRINT,
129     SP_ARG_EXPORT_PNG,
130     SP_ARG_EXPORT_DPI,
131     SP_ARG_EXPORT_AREA,
132     SP_ARG_EXPORT_AREA_DRAWING,
133     SP_ARG_EXPORT_AREA_PAGE,
134     SP_ARG_EXPORT_AREA_SNAP,
135     SP_ARG_EXPORT_WIDTH,
136     SP_ARG_EXPORT_HEIGHT,
137     SP_ARG_EXPORT_ID,
138     SP_ARG_EXPORT_ID_ONLY,
139     SP_ARG_EXPORT_USE_HINTS,
140     SP_ARG_EXPORT_BACKGROUND,
141     SP_ARG_EXPORT_BACKGROUND_OPACITY,
142     SP_ARG_EXPORT_SVG,
143     SP_ARG_EXPORT_PS,
144     SP_ARG_EXPORT_EPS,
145     SP_ARG_EXPORT_PDF,
146     SP_ARG_EXPORT_LATEX,
147 #ifdef WIN32
148     SP_ARG_EXPORT_EMF,
149 #endif //WIN32
150     SP_ARG_EXPORT_TEXT_TO_PATH,
151     SP_ARG_EXPORT_IGNORE_FILTERS,
152     SP_ARG_EXTENSIONDIR,
153     SP_ARG_QUERY_X,
154     SP_ARG_QUERY_Y,
155     SP_ARG_QUERY_WIDTH,
156     SP_ARG_QUERY_HEIGHT,
157     SP_ARG_QUERY_ALL,
158     SP_ARG_QUERY_ID,
159     SP_ARG_SHELL,
160     SP_ARG_VERSION,
161     SP_ARG_VACUUM_DEFS,
162     SP_ARG_VERB_LIST,
163     SP_ARG_VERB,
164     SP_ARG_SELECT,
165     SP_ARG_LAST
166 };
168 int sp_main_gui(int argc, char const **argv);
169 int sp_main_console(int argc, char const **argv);
170 static void sp_do_export_png(SPDocument *doc);
171 static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const *mime);
172 #ifdef WIN32
173 static void do_export_emf(SPDocument* doc, gchar const* uri, char const *mime);
174 #endif //WIN32
175 static void do_query_dimension (SPDocument *doc, bool extent, Geom::Dim2 const axis, const gchar *id);
176 static void do_query_all (SPDocument *doc);
177 static void do_query_all_recurse (SPObject *o);
179 static gchar *sp_global_printer = NULL;
180 static gchar *sp_export_png = NULL;
181 static gchar *sp_export_dpi = NULL;
182 static gchar *sp_export_area = NULL;
183 static gboolean sp_export_area_drawing = FALSE;
184 static gboolean sp_export_area_page = FALSE;
185 static gboolean sp_export_latex = FALSE;
186 static gchar *sp_export_width = NULL;
187 static gchar *sp_export_height = NULL;
188 static gchar *sp_export_id = NULL;
189 static gchar *sp_export_background = NULL;
190 static gchar *sp_export_background_opacity = NULL;
191 static gboolean sp_export_area_snap = FALSE;
192 static gboolean sp_export_use_hints = FALSE;
193 static gboolean sp_export_id_only = FALSE;
194 static gchar *sp_export_svg = NULL;
195 static gchar *sp_export_ps = NULL;
196 static gchar *sp_export_eps = NULL;
197 static gchar *sp_export_pdf = NULL;
198 #ifdef WIN32
199 static gchar *sp_export_emf = NULL;
200 #endif //WIN32
201 static gboolean sp_export_text_to_path = FALSE;
202 static gboolean sp_export_ignore_filters = FALSE;
203 static gboolean sp_export_font = FALSE;
204 static gboolean sp_query_x = FALSE;
205 static gboolean sp_query_y = FALSE;
206 static gboolean sp_query_width = FALSE;
207 static gboolean sp_query_height = FALSE;
208 static gboolean sp_query_all = FALSE;
209 static gchar *sp_query_id = NULL;
210 static gboolean sp_shell = FALSE;
211 static gboolean sp_vacuum_defs = FALSE;
213 static gchar *sp_export_png_utf8 = NULL;
214 static gchar *sp_export_svg_utf8 = NULL;
215 static gchar *sp_global_printer_utf8 = NULL;
218 /**
219  *  Reset variables to default values.
220  */
221 static void resetCommandlineGlobals() {
222         sp_global_printer = NULL;
223         sp_export_png = NULL;
224         sp_export_dpi = NULL;
225         sp_export_area = NULL;
226         sp_export_area_drawing = FALSE;
227         sp_export_area_page = FALSE;
228         sp_export_latex = FALSE;
229         sp_export_width = NULL;
230         sp_export_height = NULL;
231         sp_export_id = NULL;
232         sp_export_background = NULL;
233         sp_export_background_opacity = NULL;
234         sp_export_area_snap = FALSE;
235         sp_export_use_hints = FALSE;
236         sp_export_id_only = FALSE;
237         sp_export_svg = NULL;
238         sp_export_ps = NULL;
239         sp_export_eps = NULL;
240         sp_export_pdf = NULL;
241 #ifdef WIN32
242         sp_export_emf = NULL;
243 #endif //WIN32
244         sp_export_text_to_path = FALSE;
245         sp_export_ignore_filters = FALSE;
246         sp_export_font = FALSE;
247         sp_query_x = FALSE;
248         sp_query_y = FALSE;
249         sp_query_width = FALSE;
250         sp_query_height = FALSE;
251         sp_query_all = FALSE;
252         sp_query_id = NULL;
253         sp_vacuum_defs = FALSE;
255         sp_export_png_utf8 = NULL;
256         sp_export_svg_utf8 = NULL;
257         sp_global_printer_utf8 = NULL;
260 #ifdef WIN32
261 static bool replaceArgs( int& argc, char**& argv );
262 #endif
263 static GSList *sp_process_args(poptContext ctx);
264 struct poptOption options[] = {
265     {"version", 'V',
266      POPT_ARG_NONE, NULL, SP_ARG_VERSION,
267      N_("Print the Inkscape version number"),
268      NULL},
270     {"without-gui", 'z',
271      POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
272      N_("Do not use X server (only process files from console)"),
273      NULL},
275     {"with-gui", 'g',
276      POPT_ARG_NONE, NULL, SP_ARG_GUI,
277      N_("Try to use X server (even if $DISPLAY is not set)"),
278      NULL},
280     {"file", 'f',
281      POPT_ARG_STRING, NULL, SP_ARG_FILE,
282      N_("Open specified document(s) (option string may be excluded)"),
283      N_("FILENAME")},
285     {"print", 'p',
286      POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
287      N_("Print document(s) to specified output file (use '| program' for pipe)"),
288      N_("FILENAME")},
290     {"export-png", 'e',
291      POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
292      N_("Export document to a PNG file"),
293      N_("FILENAME")},
295     {"export-dpi", 'd',
296      POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
297      N_("Resolution for exporting to bitmap and for rasterization of filters in PS/EPS/PDF (default 90)"),
298      N_("DPI")},
300     {"export-area", 'a',
301      POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
302      N_("Exported area in SVG user units (default is the page; 0,0 is lower-left corner)"),
303      N_("x0:y0:x1:y1")},
305     {"export-area-drawing", 'D',
306      POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
307      N_("Exported area is the entire drawing (not page)"),
308      NULL},
310     {"export-area-page", 'C',
311      POPT_ARG_NONE, &sp_export_area_page, SP_ARG_EXPORT_AREA_PAGE,
312      N_("Exported area is the entire page"),
313      NULL},
315     {"export-area-snap", 0,
316      POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
317      N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
318      NULL},
320     {"export-width", 'w',
321      POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
322      N_("The width of exported bitmap in pixels (overrides export-dpi)"),
323      N_("WIDTH")},
325     {"export-height", 'h',
326      POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
327      N_("The height of exported bitmap in pixels (overrides export-dpi)"),
328      N_("HEIGHT")},
330     {"export-id", 'i',
331      POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
332      N_("The ID of the object to export"),
333      N_("ID")},
335     {"export-id-only", 'j',
336      POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
337      // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
338      //  See "man inkscape" for details.
339      N_("Export just the object with export-id, hide all others (only with export-id)"),
340      NULL},
342     {"export-use-hints", 't',
343      POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
344      N_("Use stored filename and DPI hints when exporting (only with export-id)"),
345      NULL},
347     {"export-background", 'b',
348      POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
349      N_("Background color of exported bitmap (any SVG-supported color string)"),
350      N_("COLOR")},
352     {"export-background-opacity", 'y',
353      POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
354      N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
355      N_("VALUE")},
357     {"export-plain-svg", 'l',
358      POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
359      N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
360      N_("FILENAME")},
362     {"export-ps", 'P',
363      POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
364      N_("Export document to a PS file"),
365      N_("FILENAME")},
367     {"export-eps", 'E',
368      POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
369      N_("Export document to an EPS file"),
370      N_("FILENAME")},
372     {"export-pdf", 'A',
373      POPT_ARG_STRING, &sp_export_pdf, SP_ARG_EXPORT_PDF,
374      N_("Export document to a PDF file"),
375      N_("FILENAME")},
377     {"export-latex", 0,
378      POPT_ARG_NONE, &sp_export_latex, SP_ARG_EXPORT_LATEX,
379      N_("Export PDF/PS/EPS without text. Besides the PDF/PS/EPS, a LaTeX file is exported, putting the text on top of the PDF/PS/EPS file. Include the result in LaTeX like: \\input{latexfile.tex}"),
380      NULL},
382 #ifdef WIN32
383     {"export-emf", 'M',
384      POPT_ARG_STRING, &sp_export_emf, SP_ARG_EXPORT_EMF,
385      N_("Export document to an Enhanced Metafile (EMF) File"),
386      N_("FILENAME")},
387 #endif //WIN32
389     {"export-text-to-path", 'T',
390      POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
391      N_("Convert text object to paths on export (PS, EPS, PDF)"),
392      NULL},
394     {"export-ignore-filters", 0,
395      POPT_ARG_NONE, &sp_export_ignore_filters, SP_ARG_EXPORT_IGNORE_FILTERS,
396      N_("Render filtered objects without filters, instead of rasterizing (PS, EPS, PDF)"),
397      NULL},
399     {"query-x", 'X',
400      POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
401      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
402      N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
403      NULL},
405     {"query-y", 'Y',
406      POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
407      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
408      N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
409      NULL},
411     {"query-width", 'W',
412      POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
413      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
414      N_("Query the width of the drawing or, if specified, of the object with --query-id"),
415      NULL},
417     {"query-height", 'H',
418      POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
419      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
420      N_("Query the height of the drawing or, if specified, of the object with --query-id"),
421      NULL},
423     {"query-all", 'S',
424      POPT_ARG_NONE, &sp_query_all, SP_ARG_QUERY_ALL,
425      N_("List id,x,y,w,h for all objects"),
426      NULL},
428     {"query-id", 'I',
429      POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
430      N_("The ID of the object whose dimensions are queried"),
431      N_("ID")},
433     {"extension-directory", 'x',
434      POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
435      // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
436      N_("Print out the extension directory and exit"),
437      NULL},
439     {"vacuum-defs", 0,
440      POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
441      N_("Remove unused definitions from the defs section(s) of the document"),
442      NULL},
444     {"verb-list", 0,
445      POPT_ARG_NONE, NULL, SP_ARG_VERB_LIST,
446      N_("List the IDs of all the verbs in Inkscape"),
447      NULL},
449     {"verb", 0,
450      POPT_ARG_STRING, NULL, SP_ARG_VERB,
451      N_("Verb to call when Inkscape opens."),
452      N_("VERB-ID")},
454     {"select", 0,
455      POPT_ARG_STRING, NULL, SP_ARG_SELECT,
456      N_("Object ID to select when Inkscape opens."),
457      N_("OBJECT-ID")},
459     {"shell", 0,
460      POPT_ARG_NONE, &sp_shell, SP_ARG_SHELL,
461      N_("Start Inkscape in interactive shell mode."),
462      NULL},
464     POPT_AUTOHELP POPT_TABLEEND
465 };
467 static bool needToRecodeParams = true;
468 gchar * blankParam = g_strdup("");
472 #ifdef WIN32
474 /**
475  * Set up the PATH and PYTHONPATH environment variables on Windows
476  * @param exe Inkscape executable directory in UTF-8
477  */
478 static void _win32_set_inkscape_env(gchar const *exe)
480     gchar const *path = g_getenv("PATH");
481     gchar const *pythonpath = g_getenv("PYTHONPATH");
483     gchar *python = g_build_filename(exe, "python", NULL);
484     gchar *scripts = g_build_filename(exe, "python", "Scripts", NULL);
485     gchar *perl = g_build_filename(exe, "python", NULL);
486     gchar *pythonlib = g_build_filename(exe, "python", "Lib", NULL);
487     gchar *pythondll = g_build_filename(exe, "python", "DLLs", NULL);
488     
489     // Python 2.x needs short paths in PYTHONPATH.
490     // Otherwise it doesn't work when Inkscape is installed in Unicode directories.
491     // g_win32_locale_filename_from_utf8 is the GLib wrapper for GetShortPathName.
492     // Remove this once we move to Python 3.0.
493     gchar *python_s = g_win32_locale_filename_from_utf8(python);
494     gchar *pythonlib_s = g_win32_locale_filename_from_utf8(pythonlib);
495     gchar *pythondll_s = g_win32_locale_filename_from_utf8(pythondll);
497     gchar *new_path;
498     gchar *new_pythonpath;
499     if (path) {
500         new_path = g_strdup_printf("%s;%s;%s;%s;%s", exe, python, scripts, perl, path);
501     } else {
502         new_path = g_strdup_printf("%s;%s;%s;%s", exe, python, scripts, perl);
503     }
504     if (pythonpath) {
505         new_pythonpath = g_strdup_printf("%s;%s;%s;%s",
506              python_s, pythonlib_s, pythondll_s, pythonpath);
507     } else {
508         new_pythonpath = g_strdup_printf("%s;%s;%s",
509             python_s, pythonlib_s, pythondll_s);
510     }
512     g_setenv("PATH", new_path, TRUE);
513     g_setenv("PYTHONPATH", new_pythonpath, TRUE);
515     /*
516     printf("PATH = %s\n\n", g_getenv("PATH"));
517     printf("PYTHONPATH = %s\n\n", g_getenv("PYTHONPATH"));
519     gchar *p = g_find_program_in_path("python");
520     if (p) {
521         printf("python in %s\n\n", p);
522         g_free(p);
523     } else {
524         printf("python not found\n\n");
525     }*/
527     g_free(python);
528     g_free(scripts);
529     g_free(perl);
530     g_free(pythonlib);
531     g_free(pythondll);
532     
533     g_free(python_s);
534     g_free(pythonlib_s);
535     g_free(pythondll_s);
537     g_free(new_path);
538     g_free(new_pythonpath);
540 #endif
542 static void set_extensions_env()
544     gchar const *pythonpath = g_getenv("PYTHONPATH");
545     gchar *extdir;
546     gchar *new_pythonpath;
547     
548 #ifdef WIN32
549     extdir = g_win32_locale_filename_from_utf8(INKSCAPE_EXTENSIONDIR);
550 #else
551     extdir = g_strdup(INKSCAPE_EXTENSIONDIR);
552 #endif
554     // On some platforms, INKSCAPE_EXTENSIONDIR is not absolute,
555     // but relative to the directory that contains the Inkscape executable.
556     // Since we spawn Python chdir'ed into the script's directory,
557     // we need to obtain the absolute path here.
558     if (!g_path_is_absolute(extdir)) {
559         gchar *curdir = g_get_current_dir();
560         gchar *extdir_new = g_build_filename(curdir, extdir, NULL);
561         g_free(extdir);
562         g_free(curdir);
563         extdir = extdir_new;
564     }
566     if (pythonpath) {
567         new_pythonpath = g_strdup_printf("%s" G_SEARCHPATH_SEPARATOR_S "%s",
568                                          extdir, pythonpath);
569         g_free(extdir);
570     } else {
571         new_pythonpath = extdir;
572     }
574     g_setenv("PYTHONPATH", new_pythonpath, TRUE);
575     g_free(new_pythonpath);
576     //printf("PYTHONPATH = %s\n", g_getenv("PYTHONPATH"));
579 /**
580  * This is the classic main() entry point of the program, though on some
581  * architectures it might be called by something else.
582  */
583 int
584 main(int argc, char **argv)
586 #ifdef HAVE_FPSETMASK
587     /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__.  It's probably
588        safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
589        the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
590     fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
591 #endif
593 #ifdef WIN32
594     gchar *exedir = g_strdup(win32_getExePath().data());
595     _win32_set_inkscape_env(exedir);
597 # ifdef ENABLE_NLS
598     // obtain short path to executable dir and pass it
599     // to bindtextdomain (it doesn't understand UTF-8)
600     gchar *shortexedir = g_win32_locale_filename_from_utf8(exedir);
601     gchar *localepath = g_build_filename(shortexedir, PACKAGE_LOCALE_DIR, NULL);
602     bindtextdomain(GETTEXT_PACKAGE, localepath);
603     g_free(shortexedir);
604     g_free(localepath);
605 # endif
606     g_free(exedir);
608     // Don't touch the registry (works fine without it) for Inkscape Portable
609     gchar const *val = g_getenv("INKSCAPE_PORTABLE_PROFILE_DIR");
610     if (!val) {
611         RegistryTool rt;
612         rt.setPathInfo();
613     }
614 #elif defined(ENABLE_NLS)
615 # ifdef ENABLE_BINRELOC
616     bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
617 # else
618     bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
619 # endif
620 #endif
622     // the bit below compiles regardless of platform
623 #ifdef ENABLE_NLS
624     // Allow the user to override the locale directory by setting
625     // the environment variable INKSCAPE_LOCALEDIR.
626     char const *inkscape_localedir = g_getenv("INKSCAPE_LOCALEDIR");
627     if (inkscape_localedir != NULL) {
628         bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
629     }
631     // common setup
632     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
633     textdomain(GETTEXT_PACKAGE);
634 #endif
636     set_extensions_env();
638     // Prevents errors like "Unable to wrap GdkPixbuf..." (in nr-filter-image.cpp for example)
639     Gtk::Main::init_gtkmm_internals();
641     LIBXML_TEST_VERSION
643     Inkscape::GC::init();
645     Inkscape::Debug::Logger::init();
647     gboolean use_gui;
649 #ifndef WIN32
650     use_gui = (g_getenv("DISPLAY") != NULL);
651 #else
652     use_gui = TRUE;
653 #endif
654     /* Test whether with/without GUI is forced */
655     for (int i = 1; i < argc; i++) {
656         if (!strcmp(argv[i], "-z")
657             || !strcmp(argv[i], "--without-gui")
658             || !strcmp(argv[i], "-p")
659             || !strncmp(argv[i], "--print", 7)
660             || !strcmp(argv[i], "-e")
661             || !strncmp(argv[i], "--export-png", 12)
662             || !strcmp(argv[i], "-l")
663             || !strncmp(argv[i], "--export-plain-svg", 18)
664             || !strcmp(argv[i], "-i")
665             || !strncmp(argv[i], "--export-area-drawing", 21)
666             || !strcmp(argv[i], "-D")
667             || !strncmp(argv[i], "--export-area-page", 18)
668             || !strcmp(argv[i], "-C")
669             || !strncmp(argv[i], "--export-id", 11)
670             || !strcmp(argv[i], "-P")
671             || !strncmp(argv[i], "--export-ps", 11)
672             || !strcmp(argv[i], "-E")
673             || !strncmp(argv[i], "--export-eps", 12)
674             || !strcmp(argv[i], "-A")
675             || !strncmp(argv[i], "--export-pdf", 12)
676             || !strncmp(argv[i], "--export-latex", 14)
677 #ifdef WIN32
678             || !strcmp(argv[i], "-M")
679             || !strncmp(argv[i], "--export-emf", 12)
680 #endif //WIN32
681             || !strcmp(argv[i], "-W")
682             || !strncmp(argv[i], "--query-width", 13)
683             || !strcmp(argv[i], "-H")
684             || !strncmp(argv[i], "--query-height", 14)
685             || !strcmp(argv[i], "-S")
686             || !strncmp(argv[i], "--query-all", 11)
687             || !strcmp(argv[i], "-X")
688             || !strncmp(argv[i], "--query-x", 9)
689             || !strcmp(argv[i], "-Y")
690             || !strncmp(argv[i], "--query-y", 9)
691             || !strcmp(argv[i], "--vacuum-defs")
692             || !strcmp(argv[i], "--shell")
693            )
694         {
695             /* main_console handles any exports -- not the gui */
696             use_gui = FALSE;
697             break;
698         } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
699             use_gui = TRUE;
700             break;
701         }
702     }
704 #ifdef WIN32
705 #ifndef REPLACEARGS_ANSI
706     if ( PrintWin32::is_os_wide() )
707 #endif // REPLACEARGS_ANSI
708     {
709         // If the call fails, we'll need to convert charsets
710         needToRecodeParams = !replaceArgs( argc, argv );
711     }
712 #endif // WIN32
714     int retcode;
716     if (use_gui) {
717         retcode = sp_main_gui(argc, (const char **) argv);
718     } else {
719         retcode = sp_main_console(argc, (const char **) argv);
720     }
722     return retcode;
728 void fixupSingleFilename( gchar **orig, gchar **spare )
730     if ( orig && *orig && **orig ) {
731         GError *error = NULL;
732         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
733         if ( newFileName )
734         {
735             *orig = newFileName;
736             if ( spare ) {
737                 *spare = newFileName;
738             }
739 //             g_message("Set a replacement fixup");
740         }
741     }
746 GSList *fixupFilenameEncoding( GSList* fl )
748     GSList *newFl = NULL;
749     while ( fl ) {
750         gchar *fn = static_cast<gchar*>(fl->data);
751         fl = g_slist_remove( fl, fl->data );
752         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
753         if ( newFileName ) {
755             if ( 0 )
756             {
757                 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
758                 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
759                 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
760                                                        "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
761                 gtk_dialog_run (GTK_DIALOG (w));
762                 gtk_widget_destroy (w);
763                 g_free(safeNewFn);
764                 g_free(safeFn);
765             }
767             g_free( fn );
768             fn = newFileName;
769             newFileName = 0;
770         }
771         else
772             if ( 0 )
773         {
774             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
775             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
776             gtk_dialog_run (GTK_DIALOG (w));
777             gtk_widget_destroy (w);
778             g_free(safeFn);
779         }
780         newFl = g_slist_append( newFl, fn );
781     }
782     return newFl;
785 int sp_common_main( int argc, char const **argv, GSList **flDest )
787     /// \todo fixme: Move these to some centralized location (Lauris)
788     sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
789     sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
792     // temporarily switch gettext encoding to locale, so that help messages can be output properly
793     gchar const *charset;
794     g_get_charset(&charset);
796     bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
798     poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
799     poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
800     g_return_val_if_fail(ctx != NULL, 1);
802     /* Collect own arguments */
803     GSList *fl = sp_process_args(ctx);
804     poptFreeContext(ctx);
806     // now switch gettext back to UTF-8 (for GUI)
807     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
809     // Now let's see if the file list still holds up
810     if ( needToRecodeParams )
811     {
812         fl = fixupFilenameEncoding( fl );
813     }
815     // Check the globals for filename-fixup
816     if ( needToRecodeParams )
817     {
818         fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
819         fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
820         fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
821     }
822     else
823     {
824         if ( sp_export_png )
825             sp_export_png_utf8 = g_strdup( sp_export_png );
826         if ( sp_export_svg )
827             sp_export_svg_utf8 = g_strdup( sp_export_svg );
828         if ( sp_global_printer )
829             sp_global_printer_utf8 = g_strdup( sp_global_printer );
830     }
832     // Return the list if wanted, else free it up.
833     if ( flDest ) {
834         *flDest = fl;
835         fl = 0;
836     } else {
837         while ( fl ) {
838             g_free( fl->data );
839             fl = g_slist_remove( fl, fl->data );
840         }
841     }
842     return 0;
845 static void
846 snooper(GdkEvent *event, gpointer /*data*/) {
847     if (inkscape_mapalt())  /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
848     {
849         GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
850         switch (event->type) {
851             case GDK_MOTION_NOTIFY:
852                 if(event->motion.state & mapping) {
853                     event->motion.state|=GDK_MOD1_MASK;
854                 }
855                 break;
856             case GDK_BUTTON_PRESS:
857                 if(event->button.state & mapping) {
858                     event->button.state|=GDK_MOD1_MASK;
859                 }
860                 break;
861              case GDK_KEY_PRESS:
862                  if(event->key.state & mapping) {
863                      event->key.state|=GDK_MOD1_MASK;
864                  }
865                  break;
866         default:
867             break;
868         }
869     }
871     if (inkscape_trackalt()) {
872         // MacOS X with X11 has some problem with the default
873         // xmodmapping.  A ~/.xmodmap solution does not work reliably due
874         // to the way we package our executable in a .app that can launch
875         // X11 or use an already-running X11.  The same problem has been
876         // reported on Linux but there is no .app/X11 to get in the way
877         // of ~/.xmodmap fixes.  So we make this a preference.
878         //
879         // For some reason, Gdk senses changes in Alt (Mod1) state for
880         // many message types, but not for keystrokes!  So this ugly hack
881         // tracks what the state of Alt-pressing is, and ensures
882         // GDK_MOD1_MASK is in the event->key.state as appropriate.
883         //
884         static gboolean altL_pressed = FALSE;
885         static gboolean altR_pressed = FALSE;
886         static gboolean alt_pressed = FALSE;
887         guint get_group0_keyval(GdkEventKey* event);
888         guint keyval = 0;
889         switch (event->type) {
890         case GDK_MOTION_NOTIFY:
891             alt_pressed = TRUE && (event->motion.state & GDK_MOD1_MASK);
892             break;
893         case GDK_BUTTON_PRESS:
894             alt_pressed = TRUE && (event->button.state & GDK_MOD1_MASK);
895             break;
896         case GDK_KEY_PRESS:
897             keyval = get_group0_keyval(&event->key);
898             if (keyval == GDK_Alt_L) altL_pressed = TRUE;
899             if (keyval == GDK_Alt_R) altR_pressed = TRUE;
900             alt_pressed = alt_pressed || altL_pressed || altR_pressed;
901             alt_pressed = alt_pressed || (event->button.state & GDK_MOD1_MASK);
902             if (alt_pressed)
903                 event->key.state |= GDK_MOD1_MASK;
904             else
905                 event->key.state &= ~GDK_MOD1_MASK;
906             break;
907         case GDK_KEY_RELEASE:
908             keyval = get_group0_keyval(&event->key);
909             if (keyval == GDK_Alt_L) altL_pressed = FALSE;
910             if (keyval == GDK_Alt_R) altR_pressed = FALSE;
911             if (!altL_pressed && !altR_pressed)
912                 alt_pressed = FALSE;
913             break;
914         default:
915             break;
916         }
917         //printf("alt_pressed: %s\n", alt_pressed? "+" : "-");
918     }
920     gtk_main_do_event (event);
923 static std::vector<Glib::ustring> getDirectorySet(const gchar* userDir, const gchar* const * systemDirs) {
924     std::vector<Glib::ustring> listing;
925     listing.push_back(userDir);
926     for ( const char* const* cur = systemDirs; *cur; cur++ )
927     {
928         listing.push_back(*cur);
929     }
930     return listing;
933 int
934 sp_main_gui(int argc, char const **argv)
936     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
938     GSList *fl = NULL;
939     int retVal = sp_common_main( argc, argv, &fl );
940     g_return_val_if_fail(retVal == 0, 1);
942     // Add possible icon entry directories
943     std::vector<Glib::ustring> dataDirs = getDirectorySet( g_get_user_data_dir(),
944                                                            g_get_system_data_dirs() );
945     for (std::vector<Glib::ustring>::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
946     {
947         std::vector<Glib::ustring> listing;
948         listing.push_back(*it);
949         listing.push_back("inkscape");
950         listing.push_back("icons");
951         Glib::ustring dir = Glib::build_filename(listing);
952         gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), dir.c_str());
953     }
955     // Add our icon directory to the search path for icon theme lookups.
956     gchar *usericondir = profile_path("icons");
957     gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), usericondir);
958     gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), INKSCAPE_PIXMAPDIR);
959     g_free(usericondir);
961     gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
962     Inkscape::Debug::log_display_config();
964     // Set default window icon. Obeys the theme.
965     gtk_window_set_default_icon_name("inkscape");
966     // Do things that were previously in inkscape_gtk_stock_init().
967     sp_icon_get_phys_size(GTK_ICON_SIZE_MENU);
968     Inkscape::UI::Widget::Panel::prep();
970     gboolean create_new = TRUE;
972     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
973     inkscape_application_init(argv[0], true);
975     while (fl) {
976         if (sp_file_open((gchar *)fl->data,NULL)) {
977             create_new=FALSE;
978         }
979         fl = g_slist_remove(fl, fl->data);
980     }
981     if (create_new) {
982         sp_file_new_default();
983     }
985     Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
986     main_instance.run();
988 #ifdef WIN32
989     //We might not need anything here
990     //sp_win32_finish(); <-- this is a NOP func
991 #endif
993     return 0;
996 /**
997  * Process file list
998  */
999 void sp_process_file_list(GSList *fl)
1001     while (fl) {
1002         const gchar *filename = (gchar *)fl->data;
1004         SPDocument *doc = NULL;
1005         try {
1006             doc = Inkscape::Extension::open(NULL, filename);
1007         } catch (Inkscape::Extension::Input::no_extension_found &e) {
1008             doc = NULL;
1009         } catch (Inkscape::Extension::Input::open_failed &e) {
1010             doc = NULL;
1011         }
1013         if (doc == NULL) {
1014             try {
1015                 doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), filename);
1016             } catch (Inkscape::Extension::Input::no_extension_found &e) {
1017                 doc = NULL;
1018             } catch (Inkscape::Extension::Input::open_failed &e) {
1019                 doc = NULL;
1020             }
1021         }
1022         if (doc == NULL) {
1023             g_warning("Specified document %s cannot be opened (does not exist or not a valid SVG file)", filename);
1024         } else {
1025             if (sp_vacuum_defs) {
1026                 vacuum_document(doc);
1027             }
1028             if (sp_vacuum_defs && !sp_export_svg) {
1029                 // save under the name given in the command line
1030                 sp_repr_save_file(doc->rdoc, filename, SP_SVG_NS_URI);
1031             }
1032             if (sp_global_printer) {
1033                 sp_print_document_to_file(doc, sp_global_printer);
1034             }
1035             if (sp_export_png || (sp_export_id && sp_export_use_hints)) {
1036                 sp_do_export_png(doc);
1037             }
1038             if (sp_export_svg) {
1039                 Inkscape::XML::Document *rdoc;
1040                 Inkscape::XML::Node *repr;
1041                 rdoc = sp_repr_document_new("svg:svg");
1042                 repr = rdoc->root();
1043                 repr = sp_document_root(doc)->updateRepr(rdoc, repr, SP_OBJECT_WRITE_BUILD);
1044                 sp_repr_save_rebased_file(repr->document(), sp_export_svg, SP_SVG_NS_URI,
1045                                           doc->base, sp_export_svg);
1046             }
1047             if (sp_export_ps) {
1048                 do_export_ps_pdf(doc, sp_export_ps, "image/x-postscript");
1049             }
1050             if (sp_export_eps) {
1051                 do_export_ps_pdf(doc, sp_export_eps, "image/x-e-postscript");
1052             }
1053             if (sp_export_pdf) {
1054                 do_export_ps_pdf(doc, sp_export_pdf, "application/pdf");
1055             }
1056 #ifdef WIN32
1057             if (sp_export_emf) {
1058                 do_export_emf(doc, sp_export_emf, "image/x-emf");
1059             }
1060 #endif //WIN32
1061             if (sp_query_all) {
1062                 do_query_all (doc);
1063             } else if (sp_query_width || sp_query_height) {
1064                 do_query_dimension (doc, true, sp_query_width? Geom::X : Geom::Y, sp_query_id);
1065             } else if (sp_query_x || sp_query_y) {
1066                 do_query_dimension (doc, false, sp_query_x? Geom::X : Geom::Y, sp_query_id);
1067             }
1069             delete doc;
1070         }
1071         fl = g_slist_remove(fl, fl->data);
1072     }
1075 /**
1076  * Run the application as an interactive shell, parsing command lines from stdin
1077  * Returns -1 on error.
1078  */
1079 int sp_main_shell(char const* command_name)
1081     int retval = 0;
1083     const unsigned int buffer_size = 4096;
1084     gchar *command_line = g_strnfill(buffer_size, 0);
1085     g_strlcpy(command_line, command_name, buffer_size);
1086     gsize offset = g_strlcat(command_line, " ", buffer_size);
1087     gsize sizeLeft = buffer_size - offset;
1088     gchar *useme = command_line + offset;
1090     fprintf(stdout, "Inkscape %s interactive shell mode. Type 'quit' to quit.\n", Inkscape::version_string);
1091     fflush(stdout);
1092     char* linedata = 0;
1093     do {
1094         fprintf(stdout, ">");
1095         fflush(stdout);
1096         if ((linedata = fgets(useme, sizeLeft, stdin))) {
1097             size_t len = strlen(useme);
1098             if ( (len >= sizeLeft - 1) || (useme[len - 1] != '\n') ) {
1099                 fprintf(stdout, "ERROR: Command line too long\n");
1100                 // Consume rest of line
1101                 retval = -1; // If the while loop completes, this remains -1
1102                 while (fgets(useme, sizeLeft, stdin) && retval) {
1103                     len = strlen(command_line);
1104                     if ( (len < buffer_size) && (command_line[len-1] == '\n') ) {
1105                         retval = 0;
1106                     }
1107                 }
1108             } else {
1109                 useme[--len] = '\0';  // Strip newline
1110                 if (useme[len - 1] == '\r') {
1111                     useme[--len] = '\0';
1112                 }
1113                 if ( strcmp(useme, "quit") == 0 ) {
1114                     // Time to quit
1115                     fflush(stdout);
1116                     linedata = 0; // mark for exit
1117                 } else if ( len < 1 ) {
1118                     // blank string. Do nothing.
1119                 } else {
1120                     GError* parseError = 0;
1121                     gchar** argv = 0;
1122                     gint argc = 0;
1123                     if ( g_shell_parse_argv(command_line, &argc, &argv, &parseError) ) {
1124                         poptContext ctx = poptGetContext(NULL, argc, const_cast<const gchar**>(argv), options, 0);
1125                         poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
1126                         if ( ctx ) {
1127                             GSList *fl = sp_process_args(ctx);
1128                             sp_process_file_list(fl);
1129                             poptFreeContext(ctx);
1130                         } else {
1131                             retval = 1; // not sure why. But this was the previous return value
1132                         }
1133                         resetCommandlineGlobals();
1134                         g_strfreev(argv);
1135                     } else {
1136                         g_warning("Cannot parse commandline: %s", useme);
1137                     }
1138                 }
1139             }
1140         } // if (linedata...
1141     } while (linedata && (retval == 0));
1143     g_free(command_line);
1144     return retval;
1147 int sp_main_console(int argc, char const **argv)
1149     /* We are started in text mode */
1151     /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
1152      * in a non-Gtk environment.  Used in libnrtype's
1153      * FontInstance.cpp and FontFactory.cpp.
1154      * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
1155      */
1156     g_type_init();
1157     char **argv2 = const_cast<char **>(argv);
1158     gtk_init_check( &argc, &argv2 );
1159     //setlocale(LC_ALL, "");
1161     GSList *fl = NULL;
1162     int retVal = sp_common_main( argc, argv, &fl );
1163     g_return_val_if_fail(retVal == 0, 1);
1165     if (fl == NULL && !sp_shell) {
1166         g_print("Nothing to do!\n");
1167         exit(0);
1168     }
1170     inkscape_application_init(argv[0], false);
1172     if (sp_shell) {
1173         sp_main_shell(argv[0]); // Run as interactive shell
1174         exit(0);
1175     } else {
1176         sp_process_file_list(fl); // Normal command line invokation
1177     }
1179     return 0;
1182 static void
1183 do_query_dimension (SPDocument *doc, bool extent, Geom::Dim2 const axis, const gchar *id)
1185     SPObject *o = NULL;
1187     if (id) {
1188         o = doc->getObjectById(id);
1189         if (o) {
1190             if (!SP_IS_ITEM (o)) {
1191                 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
1192                 return;
1193             }
1194         } else {
1195             g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
1196             return;
1197         }
1198     } else {
1199         o = SP_DOCUMENT_ROOT(doc);
1200     }
1202     if (o) {
1203         sp_document_ensure_up_to_date (doc);
1204         SPItem *item = ((SPItem *) o);
1206         // "true" SVG bbox for scripting
1207         Geom::OptRect area = item->getBounds(sp_item_i2doc_affine(item));
1208         if (area) {
1209             Inkscape::SVGOStringStream os;
1210             if (extent) {
1211                 os << area->dimensions()[axis];
1212             } else {
1213                 os << area->min()[axis];
1214             }
1215             g_print ("%s", os.str().c_str());
1216         } else {
1217             g_print("0");
1218         }
1219     }
1222 static void
1223 do_query_all (SPDocument *doc)
1225     SPObject *o = NULL;
1227     o = SP_DOCUMENT_ROOT(doc);
1229     if (o) {
1230         sp_document_ensure_up_to_date (doc);
1231         do_query_all_recurse(o);
1232     }
1235 static void
1236 do_query_all_recurse (SPObject *o)
1238     SPItem *item = ((SPItem *) o);
1239     if (o->getId() && SP_IS_ITEM(item)) {
1240         Geom::OptRect area = item->getBounds(sp_item_i2doc_affine(item));
1241         if (area) {
1242             Inkscape::SVGOStringStream os;
1243             os << o->getId();
1244             os << "," << area->min()[Geom::X];
1245             os << "," << area->min()[Geom::Y];
1246             os << "," << area->dimensions()[Geom::X];
1247             os << "," << area->dimensions()[Geom::Y];
1248             g_print ("%s\n", os.str().c_str());
1249         }
1250     }
1252     SPObject *child = o->children;
1253     while (child) {
1254         do_query_all_recurse (child);
1255         child = child->next;
1256     }
1260 static void
1261 sp_do_export_png(SPDocument *doc)
1263     const gchar *filename = NULL;
1264     bool filename_from_hint = false;
1265     gdouble dpi = 0.0;
1267     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
1268         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
1269     }
1271     GSList *items = NULL;
1273     Geom::Rect area;
1274     if (sp_export_id || sp_export_area_drawing) {
1276         SPObject *o = NULL;
1277         SPObject *o_area = NULL;
1278         if (sp_export_id && sp_export_area_drawing) {
1279             o = doc->getObjectById(sp_export_id);
1280             o_area = SP_DOCUMENT_ROOT (doc);
1281         } else if (sp_export_id) {
1282             o = doc->getObjectById(sp_export_id);
1283             o_area = o;
1284         } else if (sp_export_area_drawing) {
1285             o = SP_DOCUMENT_ROOT (doc);
1286             o_area = o;
1287         }
1289         if (o) {
1290             if (!SP_IS_ITEM (o)) {
1291                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
1292                 return;
1293             }
1295             items = g_slist_prepend (items, SP_ITEM(o));
1297             if (sp_export_id_only) {
1298                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
1299             }
1301             if (sp_export_use_hints) {
1303                 // retrieve export filename hint
1304                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
1305                 if (fn_hint) {
1306                     if (sp_export_png) {
1307                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
1308                         filename = sp_export_png;
1309                     } else {
1310                         filename = fn_hint;
1311                         filename_from_hint = true;
1312                     }
1313                 } else {
1314                     g_warning ("Export filename hint not found for the object.");
1315                     filename = sp_export_png;
1316                 }
1318                 // retrieve export dpi hints
1319                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
1320                 if (dpi_hint) {
1321                     if (sp_export_dpi || sp_export_width || sp_export_height) {
1322                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
1323                     } else {
1324                         dpi = atof(dpi_hint);
1325                     }
1326                 } else {
1327                     g_warning ("Export DPI hint not found for the object.");
1328                 }
1330             }
1332             // write object bbox to area
1333             sp_document_ensure_up_to_date (doc);
1334             Geom::OptRect areaMaybe;
1335             sp_item_invoke_bbox((SPItem *) o_area, areaMaybe, sp_item_i2d_affine((SPItem *) o_area), TRUE);
1336             if (areaMaybe) {
1337                 area = *areaMaybe;
1338             } else {
1339                 g_warning("Unable to determine a valid bounding box. Nothing exported.");
1340                 return;
1341             }
1342         } else {
1343             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1344             return;
1345         }
1346     }
1348     if (sp_export_area) {
1349         /* Try to parse area (given in SVG pixels) */
1350         gdouble x0,y0,x1,y1;
1351         if (sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &x0, &y0, &x1, &y1) != 4) {
1352             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
1353             return;
1354         }
1355         area = Geom::Rect(Geom::Interval(x0,x1), Geom::Interval(y0,y1));
1356     } else if (sp_export_area_page || !(sp_export_id || sp_export_area_drawing)) {
1357         /* Export the whole page: note: Inkscape uses 'page' in all menus and dialogs, not 'canvas' */
1358         sp_document_ensure_up_to_date (doc);
1359         Geom::Point origin (SP_ROOT(doc->root)->x.computed, SP_ROOT(doc->root)->y.computed);
1360         area = Geom::Rect(origin, origin + sp_document_dimensions(doc));
1361     }
1363     // set filename and dpi from options, if not yet set from the hints
1364     if (!filename) {
1365         if (!sp_export_png) {
1366             g_warning ("No export filename given and no filename hint. Nothing exported.");
1367             return;
1368         }
1369         filename = sp_export_png;
1370     }
1372     if (sp_export_dpi && dpi == 0.0) {
1373         dpi = atof(sp_export_dpi);
1374         if ((dpi < 0.1) || (dpi > 10000.0)) {
1375             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1376             return;
1377         }
1378         g_print("DPI: %g\n", dpi);
1379     }
1381     if (sp_export_area_snap) {
1382         round_rectangle_outwards(area);
1383     }
1385     // default dpi
1386     if (dpi == 0.0) {
1387         dpi = PX_PER_IN;
1388     }
1390     unsigned long int width = 0;
1391     unsigned long int height = 0;
1393     if (sp_export_width) {
1394         errno=0;
1395         width = strtoul(sp_export_width, NULL, 0);
1396         if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
1397             g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
1398             return;
1399         }
1400         dpi = (gdouble) width * PX_PER_IN / area.width();
1401     }
1403     if (sp_export_height) {
1404         errno=0;
1405         height = strtoul(sp_export_height, NULL, 0);
1406         if ((height < 1) || (height > PNG_UINT_31_MAX)) {
1407             g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
1408             return;
1409         }
1410         dpi = (gdouble) height * PX_PER_IN / area.height();
1411     }
1413     if (!sp_export_width) {
1414         width = (unsigned long int) (area.width() * dpi / PX_PER_IN + 0.5);
1415     }
1417     if (!sp_export_height) {
1418         height = (unsigned long int) (area.height() * dpi / PX_PER_IN + 0.5);
1419     }
1421     guint32 bgcolor = 0x00000000;
1422     if (sp_export_background) {
1423         // override the page color
1424         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1425         bgcolor |= 0xff; // default is no opacity
1426     } else {
1427         // read from namedview
1428         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1429         if (nv && nv->attribute("pagecolor"))
1430             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1431         if (nv && nv->attribute("inkscape:pageopacity"))
1432             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1433     }
1435     if (sp_export_background_opacity) {
1436         // override opacity
1437         gfloat value;
1438         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1439             if (value > 1.0) {
1440                 value = CLAMP (value, 1.0f, 255.0f);
1441                 bgcolor &= (guint32) 0xffffff00;
1442                 bgcolor |= (guint32) floor(value);
1443             } else {
1444                 value = CLAMP (value, 0.0f, 1.0f);
1445                 bgcolor &= (guint32) 0xffffff00;
1446                 bgcolor |= SP_COLOR_F_TO_U(value);
1447             }
1448         }
1449     }
1451     gchar *path = 0;
1452     if (filename_from_hint) {
1453         //Make relative paths go from the document location, if possible:
1454         if (!g_path_is_absolute(filename) && doc->uri) {
1455             gchar *dirname = g_path_get_dirname(doc->uri);
1456             if (dirname) {
1457                 path = g_build_filename(dirname, filename, NULL);
1458                 g_free(dirname);
1459             }
1460         }
1461         if (!path) {
1462             path = g_strdup(filename);
1463         }
1464     } else {
1465         path = g_strdup(filename);
1466     }
1468     g_print("Background RRGGBBAA: %08x\n", bgcolor);
1470     g_print("Area %g:%g:%g:%g exported to %lu x %lu pixels (%g dpi)\n", area[Geom::X][0], area[Geom::Y][0], area[Geom::X][1], area[Geom::Y][1], width, height, dpi);
1472     g_print("Bitmap saved as: %s\n", filename);
1474     if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1475         sp_export_png_file(doc, path, area, width, height, dpi, dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : NULL);
1476     } else {
1477         g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1478     }
1480     g_free (path);
1481     g_slist_free (items);
1485 /**
1486  *  Perform a PDF/PS/EPS export
1487  *
1488  *  \param doc Document to export.
1489  *  \param uri URI to export to.
1490  *  \param mime MIME type to export as.
1491  */
1493 static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1495     Inkscape::Extension::DB::OutputList o;
1496     Inkscape::Extension::db.get_output_list(o);
1497     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1498     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1499         i++;
1500     }
1502     if (i == o.end())
1503     {
1504         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1505         return;
1506     }
1508     if (sp_export_id) {
1509         SPObject *o = doc->getObjectById(sp_export_id);
1510         if (o == NULL) {
1511             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1512             return;
1513         }
1514         (*i)->set_param_string ("exportId", sp_export_id);
1515     } else {
1516         (*i)->set_param_string ("exportId", "");
1517     }
1519     if (sp_export_area_page && sp_export_area_drawing) {
1520         g_warning ("You cannot use --export-area-page and --export-area-drawing at the same time; only the former will take effect.");
1521         sp_export_area_drawing = false;
1522     }
1524     if (sp_export_area_drawing) {
1525         (*i)->set_param_bool ("areaDrawing", TRUE);
1526     } else {
1527         (*i)->set_param_bool ("areaDrawing", FALSE);
1528     }
1530     if (sp_export_area_page) {
1531         if (sp_export_eps) {
1532             g_warning ("EPS cannot have its bounding box extend beyond its content, so if your drawing is smaller than the page, --export-area-page will clip it to drawing.");
1533         }
1534         (*i)->set_param_bool ("areaPage", TRUE);
1535     } else {
1536         (*i)->set_param_bool ("areaPage", FALSE);
1537     }
1539     if (!sp_export_area_drawing && !sp_export_area_page && !sp_export_id) {
1540         // neither is set, set page as default for ps/pdf and drawing for eps
1541         if (sp_export_eps) {
1542             try {
1543                (*i)->set_param_bool("areaDrawing", TRUE);
1544             } catch (...) {}
1545         }
1546     }
1548     if (sp_export_text_to_path) {
1549         (*i)->set_param_bool("textToPath", TRUE);
1550     } else {
1551         (*i)->set_param_bool("textToPath", FALSE);
1552     }
1554     if (sp_export_latex) {
1555         (*i)->set_param_bool("textToLaTeX", TRUE);
1556     } else {
1557         (*i)->set_param_bool("textToLaTeX", FALSE);
1558     }
1560     if (sp_export_ignore_filters) {
1561         (*i)->set_param_bool("blurToBitmap", FALSE);
1562     } else {
1563         (*i)->set_param_bool("blurToBitmap", TRUE);
1565         gdouble dpi = 90.0;
1566         if (sp_export_dpi) {
1567             dpi = atof(sp_export_dpi);
1568             if ((dpi < 1) || (dpi > 10000.0)) {
1569                 g_warning("DPI value %s out of range [1 - 10000]. Using 90 dpi instead.", sp_export_dpi);
1570                 dpi = 90;
1571             }
1572         }
1574         (*i)->set_param_int("resolution", (int) dpi);
1575     }
1577     (*i)->save(doc, uri);
1580 #ifdef WIN32
1581 /**
1582  *  Export a document to EMF
1583  *
1584  *  \param doc Document to export.
1585  *  \param uri URI to export to.
1586  *  \param mime MIME type to export as (should be "image/x-emf")
1587  */
1589 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1591     Inkscape::Extension::DB::OutputList o;
1592     Inkscape::Extension::db.get_output_list(o);
1593     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1594     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1595         i++;
1596     }
1598     if (i == o.end())
1599     {
1600         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1601         return;
1602     }
1604     (*i)->save(doc, uri);
1606 #endif //WIN32
1608 #ifdef WIN32
1609 bool replaceArgs( int& argc, char**& argv )
1611     bool worked = false;
1613 #ifdef REPLACEARGS_DEBUG
1614     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1615 #endif // REPLACEARGS_DEBUG
1617     wchar_t* line = GetCommandLineW();
1618     if ( line )
1619     {
1620 #ifdef REPLACEARGS_DEBUG
1621         {
1622             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1623             if ( utf8Line )
1624             {
1625                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1626                 {
1627                     char tmp[strlen(safe) + 32];
1628                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1629                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1630                 }
1631             }
1632         }
1633 #endif // REPLACEARGS_DEBUG
1635         int numArgs = 0;
1636         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1638 #ifdef REPLACEARGS_ANSI
1639 // test code for trying things on Win95/98/ME
1640         if ( !parsed )
1641         {
1642 #ifdef REPLACEARGS_DEBUG
1643             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1644 #endif // REPLACEARGS_DEBUG
1645             int lineLen = wcslen(line) + 1;
1646             wchar_t* lineDup = new wchar_t[lineLen];
1647             wcsncpy( lineDup, line, lineLen );
1649             int pos = 0;
1650             bool inQuotes = false;
1651             bool inWhitespace = true;
1652             std::vector<int> places;
1653             while ( lineDup[pos] )
1654             {
1655                 if ( inQuotes )
1656                 {
1657                     if ( lineDup[pos] == L'"' )
1658                     {
1659                         inQuotes = false;
1660                     }
1661                 }
1662                 else if ( lineDup[pos] == L'"' )
1663                 {
1664                     inQuotes = true;
1665                     inWhitespace = false;
1666                     places.push_back(pos);
1667                 }
1668                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1669                 {
1670                     if ( !inWhitespace )
1671                     {
1672                         inWhitespace = true;
1673                         lineDup[pos] = 0;
1674                     }
1675                 }
1676                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1677                 {
1678                     inWhitespace = false;
1679                     places.push_back(pos);
1680                 }
1681                 else
1682                 {
1683                     // consume
1684                 }
1685                 pos++;
1686             }
1687 #ifdef REPLACEARGS_DEBUG
1688             {
1689                 char tmp[256];
1690                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1691                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1692             }
1693 #endif // REPLACEARGS_DEBUG
1695             wchar_t** block = new wchar_t*[places.size()];
1696             int i = 0;
1697             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1698             {
1699                 block[i++] = &lineDup[*it];
1700             }
1701             parsed = block;
1702             numArgs = places.size();
1703         }
1704 #endif // REPLACEARGS_ANSI
1706         if ( parsed )
1707         {
1708             std::vector<wchar_t*>expandedArgs;
1709             if ( numArgs > 0 )
1710             {
1711                 expandedArgs.push_back( parsed[0] );
1712             }
1714             for ( int i1 = 1; i1 < numArgs; i1++ )
1715             {
1716                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1717                 wildcarded &= parsed[i1][0] != L'"';
1718                 wildcarded &= parsed[i1][0] != L'-';
1719                 if ( wildcarded )
1720                 {
1721 #ifdef REPLACEARGS_ANSI
1722                     WIN32_FIND_DATAA data;
1723 #else
1724                     WIN32_FIND_DATAW data;
1725 #endif // REPLACEARGS_ANSI
1727                     memset((void *)&data, 0, sizeof(data));
1729                     int baseLen = wcslen(parsed[i1]) + 2;
1730                     wchar_t* base = new wchar_t[baseLen];
1731                     wcsncpy( base, parsed[i1], baseLen );
1732                     wchar_t* last = wcsrchr( base, L'\\' );
1733                     if ( last )
1734                     {
1735                         last[1] = 0;
1736                     }
1737                     else
1738                     {
1739                         base[0] = 0;
1740                     }
1741                     baseLen = wcslen( base );
1743 #ifdef REPLACEARGS_ANSI
1744                     char target[MAX_PATH];
1745                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1746                     {
1747                         HANDLE hf = FindFirstFileA( target, &data );
1748 #else
1749                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1750 #endif // REPLACEARGS_ANSI
1751                         if ( hf != INVALID_HANDLE_VALUE )
1752                         {
1753                             BOOL found = TRUE;
1754                             do
1755                             {
1756 #ifdef REPLACEARGS_ANSI
1757                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1758                                 if ( howMany > 0 )
1759                                 {
1760                                     howMany += baseLen;
1761                                     wchar_t* tmp = new wchar_t[howMany + 1];
1762                                     wcsncpy( tmp, base, howMany + 1 );
1763                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1764                                     expandedArgs.push_back( tmp );
1765                                     found = FindNextFileA( hf, &data );
1766                                 }
1767 #else
1768                                 int howMany = wcslen(data.cFileName) + baseLen;
1769                                 wchar_t* tmp = new wchar_t[howMany + 1];
1770                                 wcsncpy( tmp, base, howMany + 1 );
1771                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1772                                 expandedArgs.push_back( tmp );
1773                                 found = FindNextFileW( hf, &data );
1774 #endif // REPLACEARGS_ANSI
1775                             } while ( found );
1777                             FindClose( hf );
1778                         }
1779                         else
1780                         {
1781                             expandedArgs.push_back( parsed[i1] );
1782                         }
1783 #ifdef REPLACEARGS_ANSI
1784                     }
1785 #endif // REPLACEARGS_ANSI
1787                     delete[] base;
1788                 }
1789                 else
1790                 {
1791                     expandedArgs.push_back( parsed[i1] );
1792                 }
1793             }
1795             {
1796                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1797                 int iz = 0;
1798                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1799                 {
1800                     block[iz++] = *it;
1801                 }
1802                 parsed = block;
1803                 numArgs = expandedArgs.size();
1804             }
1806             std::vector<gchar*> newArgs;
1807             for ( int i = 0; i < numArgs; i++ )
1808             {
1809                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1810                 if ( replacement )
1811                 {
1812 #ifdef REPLACEARGS_DEBUG
1813                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1815                     if ( safe2 )
1816                     {
1817                         {
1818                             char tmp[1024];
1819                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1820                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1821                         }
1822                         g_free( safe2 );
1823                     }
1824 #endif // REPLACEARGS_DEBUG
1826                     newArgs.push_back( replacement );
1827                 }
1828                 else
1829                 {
1830                     newArgs.push_back( blankParam );
1831                 }
1832             }
1834             // Now push our munged params to be the new argv and argc
1835             {
1836                 char** block = new char*[newArgs.size()];
1837                 int iz = 0;
1838                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1839                 {
1840                     block[iz++] = *it;
1841                 }
1842                 argv = block;
1843                 argc = newArgs.size();
1844                 worked = true;
1845             }
1846         }
1847 #ifdef REPLACEARGS_DEBUG
1848         else
1849         {
1850             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1851         }
1852 #endif // REPLACEARGS_DEBUG
1853     }
1854 #ifdef REPLACEARGS_DEBUG
1855     else
1856     {
1857         {
1858             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1859         }
1861         char* line2 = GetCommandLineA();
1862         if ( line2 )
1863         {
1864             gchar *safe = Inkscape::IO::sanitizeString(line2);
1865             {
1866                 {
1867                     char tmp[strlen(safe) + 32];
1868                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1869                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1870                 }
1871             }
1872         }
1873         else
1874         {
1875             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1876         }
1877     }
1878 #endif // REPLACEARGS_DEBUG
1880     return worked;
1882 #endif // WIN32
1884 static GSList *
1885 sp_process_args(poptContext ctx)
1887     GSList *fl = NULL;
1889     gint a;
1890     while ((a = poptGetNextOpt(ctx)) != -1) {
1891         switch (a) {
1892             case SP_ARG_FILE: {
1893                 gchar const *fn = poptGetOptArg(ctx);
1894                 if (fn != NULL) {
1895                     fl = g_slist_append(fl, g_strdup(fn));
1896                 }
1897                 break;
1898             }
1899             case SP_ARG_VERSION: {
1900                 printf("Inkscape %s (%s)\n", Inkscape::version_string, __DATE__);
1901                 exit(0);
1902                 break;
1903             }
1904             case SP_ARG_EXTENSIONDIR: {
1905                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1906                 exit(0);
1907                 break;
1908             }
1909             case SP_ARG_VERB_LIST: {
1910                 // This really shouldn't go here, we should init the app.
1911                 // But, since we're just exiting in this path, there is
1912                 // no harm, and this is really a better place to put
1913                 // everything else.
1914                 Inkscape::Extension::init();
1915                 Inkscape::Verb::list();
1916                 exit(0);
1917                 break;
1918             }
1919             case SP_ARG_VERB:
1920             case SP_ARG_SELECT: {
1921                 gchar const *arg = poptGetOptArg(ctx);
1922                 if (arg != NULL) {
1923                     // printf("Adding in: %s\n", arg);
1924                     new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1925                 }
1926                 break;
1927             }
1928             case POPT_ERROR_BADOPT: {
1929                 g_warning ("Invalid option %s", poptBadOption(ctx, 0));
1930                 exit(1);
1931                 break;
1932             }
1933             default: {
1934                 break;
1935             }
1936         }
1937     }
1939     gchar const ** const args = poptGetArgs(ctx);
1940     if (args != NULL) {
1941         for (unsigned i = 0; args[i] != NULL; i++) {
1942             fl = g_slist_append(fl, g_strdup(args[i]));
1943         }
1944     }
1946     return fl;
1950 /*
1951   Local Variables:
1952   mode:c++
1953   c-file-style:"stroustrup"
1954   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1955   indent-tabs-mode:nil
1956   fill-column:99
1957   End:
1958 */
1959 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :