Code

Fixing scrollbar size for embeded color swatches.
[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 #include <gtk/gtkmessagedialog.h>
33 #ifdef HAVE_IEEEFP_H
34 #include <ieeefp.h>
35 #endif
36 #include <string.h>
37 #include <locale.h>
39 #include <popt.h>
40 #ifndef POPT_TABLEEND
41 #define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
42 #endif /* Not def: POPT_TABLEEND */
44 #include <libxml/tree.h>
45 #include <glib-object.h>
46 #include <gtk/gtkmain.h>
47 #include <gtk/gtksignal.h>
48 #include <gtk/gtkwindow.h>
49 #include <gtk/gtkbox.h>
51 #include <gtk/gtkmain.h>
53 #include "gc-core.h"
55 #include "macros.h"
56 #include "file.h"
57 #include "document.h"
58 #include "sp-object.h"
59 #include "interface.h"
60 #include "print.h"
61 #include "slideshow.h"
62 #include "color.h"
63 #include "sp-item.h"
64 #include "sp-root.h"
65 #include "unit-constants.h"
67 #include "svg/svg.h"
68 #include "svg/stringstream.h"
70 #include "inkscape-private.h"
71 #include "inkscape-stock.h"
72 #include "inkscape_version.h"
74 #include "sp-namedview.h"
75 #include "sp-guide.h"
76 #include "sp-object-repr.h"
77 #include "xml/repr.h"
79 #include "io/sys.h"
81 #include "debug/logger.h"
83 #include <extension/extension.h>
84 #include <extension/system.h>
85 #include <extension/db.h>
86 #include <extension/output.h>
88 #ifdef WIN32
89 //#define REPLACEARGS_ANSI
90 //#define REPLACEARGS_DEBUG
92 #include "registrytool.h"
94 #include "extension/internal/win32.h"
95 using Inkscape::Extension::Internal::PrintWin32;
97 #endif // WIN32
99 #include "extension/init.h"
101 #include <glibmm/i18n.h>
102 #include <gtkmm/main.h>
104 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
105 #define bind_textdomain_codeset(p,c)
106 #endif
108 #include "application/application.h"
110 enum {
111     SP_ARG_NONE,
112     SP_ARG_NOGUI,
113     SP_ARG_GUI,
114     SP_ARG_FILE,
115     SP_ARG_PRINT,
116     SP_ARG_EXPORT_PNG,
117     SP_ARG_EXPORT_DPI,
118     SP_ARG_EXPORT_AREA,
119     SP_ARG_EXPORT_AREA_DRAWING,
120     SP_ARG_EXPORT_AREA_SNAP,
121     SP_ARG_EXPORT_WIDTH,
122     SP_ARG_EXPORT_HEIGHT,
123     SP_ARG_EXPORT_ID,
124     SP_ARG_EXPORT_ID_ONLY,
125     SP_ARG_EXPORT_USE_HINTS,
126     SP_ARG_EXPORT_BACKGROUND,
127     SP_ARG_EXPORT_BACKGROUND_OPACITY,
128     SP_ARG_EXPORT_SVG,
129     SP_ARG_EXPORT_PS,
130     SP_ARG_EXPORT_EPS,
131     SP_ARG_EXPORT_TEXT_TO_PATH,
132     SP_ARG_EXPORT_BBOX_PAGE,
133     SP_ARG_EXTENSIONDIR,
134     SP_ARG_SLIDESHOW,
135     SP_ARG_QUERY_X,
136     SP_ARG_QUERY_Y,
137     SP_ARG_QUERY_WIDTH,
138     SP_ARG_QUERY_HEIGHT,
139     SP_ARG_QUERY_ID,
140     SP_ARG_VERSION,
141     SP_ARG_NEW_GUI,
142     SP_ARG_VACUUM_DEFS,
143     SP_ARG_LAST
144 };
146 int sp_main_gui(int argc, char const **argv);
147 int sp_main_console(int argc, char const **argv);
148 static void sp_do_export_png(SPDocument *doc);
149 static void do_export_ps(SPDocument* doc, gchar const* uri, char const *mime);
150 static void do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id);
153 static gchar *sp_global_printer = NULL;
154 static gboolean sp_global_slideshow = FALSE;
155 static gchar *sp_export_png = NULL;
156 static gchar *sp_export_dpi = NULL;
157 static gchar *sp_export_area = NULL;
158 static gboolean sp_export_area_drawing = FALSE;
159 static gchar *sp_export_width = NULL;
160 static gchar *sp_export_height = NULL;
161 static gchar *sp_export_id = NULL;
162 static gchar *sp_export_background = NULL;
163 static gchar *sp_export_background_opacity = NULL;
164 static gboolean sp_export_area_snap = FALSE;
165 static gboolean sp_export_use_hints = FALSE;
166 static gboolean sp_export_id_only = FALSE;
167 static gchar *sp_export_svg = NULL;
168 static gchar *sp_export_ps = NULL;
169 static gchar *sp_export_eps = NULL;
170 static gboolean sp_export_text_to_path = FALSE;
171 static gboolean sp_export_bbox_page = FALSE;
172 static gboolean sp_query_x = FALSE;
173 static gboolean sp_query_y = FALSE;
174 static gboolean sp_query_width = FALSE;
175 static gboolean sp_query_height = FALSE;
176 static gchar *sp_query_id = NULL;
177 static int sp_new_gui = FALSE;
178 static gboolean sp_vacuum_defs = FALSE;
180 static gchar *sp_export_png_utf8 = NULL;
181 static gchar *sp_export_svg_utf8 = NULL;
182 static gchar *sp_global_printer_utf8 = NULL;
184 #ifdef WIN32
185 static bool replaceArgs( int& argc, char**& argv );
186 #endif
187 static GSList *sp_process_args(poptContext ctx);
188 struct poptOption options[] = {
189     {"version", 'V',
190      POPT_ARG_NONE, NULL, SP_ARG_VERSION,
191      N_("Print the Inkscape version number"),
192      NULL},
194     {"without-gui", 'z',
195      POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
196      N_("Do not use X server (only process files from console)"),
197      NULL},
199     {"with-gui", 'g',
200      POPT_ARG_NONE, NULL, SP_ARG_GUI,
201      N_("Try to use X server (even if $DISPLAY is not set)"),
202      NULL},
204     {"file", 'f',
205      POPT_ARG_STRING, NULL, SP_ARG_FILE,
206      N_("Open specified document(s) (option string may be excluded)"),
207      N_("FILENAME")},
209     {"print", 'p',
210      POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
211      N_("Print document(s) to specified output file (use '| program' for pipe)"),
212      N_("FILENAME")},
214     {"export-png", 'e',
215      POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
216      N_("Export document to a PNG file"),
217      N_("FILENAME")},
219     {"export-dpi", 'd',
220      POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
221      N_("The resolution used for exporting SVG into bitmap (default 90)"),
222      N_("DPI")},
224     {"export-area", 'a',
225      POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
226      N_("Exported area in SVG user units (default is the canvas; 0,0 is lower-left corner)"),
227      N_("x0:y0:x1:y1")},
229     {"export-area-drawing", 'D',
230      POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
231      N_("Exported area is the entire drawing (not canvas)"),
232      NULL},
234     {"export-area-snap", 0,
235      POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
236      N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
237      NULL},
239     {"export-width", 'w',
240      POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
241      N_("The width of exported bitmap in pixels (overrides export-dpi)"),
242      N_("WIDTH")},
244     {"export-height", 'h',
245      POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
246      N_("The height of exported bitmap in pixels (overrides export-dpi)"),
247      N_("HEIGHT")},
249     {"export-id", 'i',
250      POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
251      N_("The ID of the object to export (overrides export-area)"),
252      N_("ID")},
254     {"export-id-only", 'j',
255      POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
256      // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
257      //  See "man inkscape" for details.
258      N_("Export just the object with export-id, hide all others (only with export-id)"),
259      NULL},
261     {"export-use-hints", 't',
262      POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
263      N_("Use stored filename and DPI hints when exporting (only with export-id)"),
264      NULL},
266     {"export-background", 'b',
267      POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
268      N_("Background color of exported bitmap (any SVG-supported color string)"),
269      N_("COLOR")},
271     {"export-background-opacity", 'y',
272      POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
273      N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
274      N_("VALUE")},
276     {"export-plain-svg", 'l',
277      POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
278      N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
279      N_("FILENAME")},
281     {"export-ps", 'P',
282      POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
283      N_("Export document to a PS file"),
284      N_("FILENAME")},
286     {"export-eps", 'E',
287      POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
288      N_("Export document to an EPS file"),
289      N_("FILENAME")},
291     {"export-text-to-path", 'T',
292      POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
293      N_("Convert text object to paths on export (EPS)"),
294      NULL},
296     {"export-bbox-page", 'B',
297      POPT_ARG_NONE, &sp_export_bbox_page, SP_ARG_EXPORT_BBOX_PAGE,
298      N_("Export files with the bounding box set to the page size (EPS)"),
299      NULL},
301     {"query-x", 'X',
302      POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
303      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
304      N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
305      NULL},
307     {"query-y", 'Y',
308      POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
309      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
310      N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
311      NULL},
313     {"query-width", 'W',
314      POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
315      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
316      N_("Query the width of the drawing or, if specified, of the object with --query-id"),
317      NULL},
319     {"query-height", 'H',
320      POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
321      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
322      N_("Query the height of the drawing or, if specified, of the object with --query-id"),
323      NULL},
325     {"query-id", 'I',
326      POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
327      N_("The ID of the object whose dimensions are queried"),
328      N_("ID")},
330     {"extension-directory", 'x',
331      POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
332      // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
333      N_("Print out the extension directory and exit"),
334      NULL},
336     {"slideshow", 's',
337      POPT_ARG_NONE, &sp_global_slideshow, SP_ARG_SLIDESHOW,
338      N_("Show given files one-by-one, switch to next on any key/mouse event"),
339      NULL},
341     {"new-gui", 'G',
342      POPT_ARG_NONE, &sp_new_gui, SP_ARG_NEW_GUI,
343      N_("Use the new Gtkmm GUI interface"),
344      NULL},
346     {"vacuum-defs", 0,
347      POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
348      N_("Remove unused definitions from the defs section(s) of the document"),
349      NULL},
351     POPT_AUTOHELP POPT_TABLEEND
352 };
354 static bool needToRecodeParams = true;
355 gchar* blankParam = "";
357 int
358 main(int argc, char **argv)
360 #ifdef HAVE_FPSETMASK
361     /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__.  It's probably
362        safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
363        the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
364     fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
365 #endif
367 #ifdef ENABLE_NLS
368 #ifdef WIN32
369     RegistryTool rt;
370     rt.setPathInfo();
371     gchar *pathBuf = g_strconcat(g_path_get_dirname(argv[0]), "\\", PACKAGE_LOCALE_DIR, NULL);
372     bindtextdomain(GETTEXT_PACKAGE, pathBuf);
373     g_free(pathBuf);
374 #else
375 #ifdef ENABLE_BINRELOC
376     bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
377 #else
378     bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
379 #endif
380 #endif
381 #endif
383     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
385 #ifdef ENABLE_NLS
386     textdomain(GETTEXT_PACKAGE);
387 #endif
389     LIBXML_TEST_VERSION
391     Inkscape::GC::init();
393     Inkscape::Debug::Logger::init();
395     gboolean use_gui;
396 #ifndef WIN32
397     use_gui = (getenv("DISPLAY") != NULL);
398 #else
399     /*
400       Set the current directory to the directory of the
401       executable.  This seems redundant, but is needed for
402       when inkscape.exe is executed from another directory.
403       We use relative paths on win32.
404       HKCR\svgfile\shell\open\command is a good example
405     */
406     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
407     char *homedir = g_path_get_dirname(argv[0]);
408     SetCurrentDirectory(homedir);
409     g_free(homedir);
411     use_gui = TRUE;
412 #endif
413     /* Test whether with/without GUI is forced */
414     for (int i = 1; i < argc; i++) {
415         if (!strcmp(argv[i], "-z")
416             || !strcmp(argv[i], "--without-gui")
417             || !strcmp(argv[i], "-p")
418             || !strncmp(argv[i], "--print", 7)
419             || !strcmp(argv[i], "-e")
420             || !strncmp(argv[i], "--export-png", 12)
421             || !strcmp(argv[i], "-l")
422             || !strncmp(argv[i], "--export-plain-svg", 12)
423             || !strcmp(argv[i], "-i")
424             || !strncmp(argv[i], "--export-area-drawing", 21)
425             || !strcmp(argv[i], "-D")
426             || !strncmp(argv[i], "--export-id", 12)
427             || !strcmp(argv[i], "-P")
428             || !strncmp(argv[i], "--export-ps", 11)
429             || !strcmp(argv[i], "-E")
430             || !strncmp(argv[i], "--export-eps", 12)
431             || !strcmp(argv[i], "-W")
432             || !strncmp(argv[i], "--query-width", 13)
433             || !strcmp(argv[i], "-H")
434             || !strncmp(argv[i], "--query-height", 14)
435             || !strcmp(argv[i], "-X")
436             || !strncmp(argv[i], "--query-x", 13)
437             || !strcmp(argv[i], "-Y")
438             || !strncmp(argv[i], "--query-y", 14)
439             || !strcmp(argv[i], "--vacuum-defs")
440            )
441         {
442             /* main_console handles any exports -- not the gui */
443             use_gui = FALSE;
444             break;
445         } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
446             use_gui = TRUE;
447             break;
448         } else if (!strcmp(argv[i], "-G") || !strcmp(argv[i], "--new-gui")) {
449             sp_new_gui = TRUE;
450             break;
451         }
452     }
454 #ifdef WIN32
455 #ifndef REPLACEARGS_ANSI
456     if ( PrintWin32::is_os_wide() )
457 #endif // REPLACEARGS_ANSI
458     {
459         // If the call fails, we'll need to convert charsets
460         needToRecodeParams = !replaceArgs( argc, argv );
461     }
462 #endif // WIN32
464     /// \todo  Should this be a static object (see inkscape.cpp)?
465     Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
467     return app.run();
470 void fixupSingleFilename( gchar **orig, gchar **spare )
472     if ( orig && *orig && **orig ) {
473         GError *error = NULL;
474         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
475         if ( newFileName )
476         {
477             *orig = newFileName;
478             if ( spare ) {
479                 *spare = newFileName;
480             }
481 //             g_message("Set a replacement fixup");
482         }
483     }
486 GSList *fixupFilenameEncoding( GSList* fl )
488     GSList *newFl = NULL;
489     while ( fl ) {
490         gchar *fn = static_cast<gchar*>(fl->data);
491         fl = g_slist_remove( fl, fl->data );
492         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
493         if ( newFileName ) {
495             if ( 0 )
496             {
497                 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
498                 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
499                 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
500                                                        "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
501                 gtk_dialog_run (GTK_DIALOG (w));
502                 gtk_widget_destroy (w);
503                 g_free(safeNewFn);
504                 g_free(safeFn);
505             }
507             g_free( fn );
508             fn = newFileName;
509             newFileName = 0;
510         }
511         else
512             if ( 0 )
513         {
514             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
515             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
516             gtk_dialog_run (GTK_DIALOG (w));
517             gtk_widget_destroy (w);
518             g_free(safeFn);
519         }
520         newFl = g_slist_append( newFl, fn );
521     }
522     return newFl;
525 int sp_common_main( int argc, char const **argv, GSList **flDest )
527     /// \todo fixme: Move these to some centralized location (Lauris)
528     sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
529     sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
532     // temporarily switch gettext encoding to locale, so that help messages can be output properly
533     gchar const *charset;
534     g_get_charset(&charset);
536     bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
538     poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
539     poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
540     g_return_val_if_fail(ctx != NULL, 1);
542     /* Collect own arguments */
543     GSList *fl = sp_process_args(ctx);
544     poptFreeContext(ctx);
546     // now switch gettext back to UTF-8 (for GUI)
547     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
549     // Now let's see if the file list still holds up
550     if ( needToRecodeParams )
551     {
552         fl = fixupFilenameEncoding( fl );
553     }
555     // Check the globals for filename-fixup
556     if ( needToRecodeParams )
557     {
558         fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
559         fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
560         fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
561     }
562     else
563     {
564         if ( sp_export_png )
565             sp_export_png_utf8 = g_strdup( sp_export_png );
566         if ( sp_export_svg )
567             sp_export_svg_utf8 = g_strdup( sp_export_svg );
568         if ( sp_global_printer )
569             sp_global_printer_utf8 = g_strdup( sp_global_printer );
570     }
572     // Return the list if wanted, else free it up.
573     if ( flDest ) {
574         *flDest = fl;
575         fl = 0;
576     } else {
577         while ( fl ) {
578             g_free( fl->data );
579             fl = g_slist_remove( fl, fl->data );
580         }
581     }
582     return 0;
585 int
586 sp_main_gui(int argc, char const **argv)
588     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
590     GSList *fl = NULL;
591     int retVal = sp_common_main( argc, argv, &fl );
592     g_return_val_if_fail(retVal == 0, 1);
594     inkscape_gtk_stock_init();
596     /* Set default icon */
597     gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
598     if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
599         gtk_window_set_default_icon_from_file(filename, NULL);
600     }
601     g_free (filename);
602     filename = 0;
604     if (!sp_global_slideshow) {
605         gboolean create_new = TRUE;
607         /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
608         inkscape_application_init(argv[0], true);
610         while (fl) {
611             if (sp_file_open((gchar *)fl->data,NULL)) {
612                 create_new=FALSE;
613             }
614             fl = g_slist_remove(fl, fl->data);
615         }
616         if (create_new) {
617             sp_file_new_default();
618         }
619     } else {
620         if (fl) {
621             GtkWidget *ss;
622             /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
623             inkscape_application_init(argv[0], true);
624             ss = sp_slideshow_new(fl);
625             if (ss) gtk_widget_show(ss);
626         } else {
627             g_warning ("No slides to display");
628             exit(0);
629         }
630     }
632     main_instance.run();
634 #ifdef WIN32
635     //We might not need anything here
636     //sp_win32_finish(); <-- this is a NOP func
637 #endif
639     return 0;
642 int
643 sp_main_console(int argc, char const **argv)
645     /* We are started in text mode */
647     /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
648      * in a non-Gtk environment.  Used in libnrtype's
649      * FontInstance.cpp and FontFactory.cpp.
650      * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
651      */
652     g_type_init();
653     char **argv2 = const_cast<char **>(argv);
654     gtk_init_check( &argc, &argv2 );
655     //setlocale(LC_ALL, "");
657     GSList *fl = NULL;
658     int retVal = sp_common_main( argc, argv, &fl );
659     g_return_val_if_fail(retVal == 0, 1);
661     if (fl == NULL) {
662         g_print("Nothing to do!\n");
663         exit(0);
664     }
666     inkscape_application_init(argv[0], false);
668     while (fl) {
669         SPDocument *doc;
671         doc = Inkscape::Extension::open(NULL, (gchar *)fl->data);
672         if (doc == NULL) {
673             doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), (gchar *)fl->data);
674         }
675         if (doc == NULL) {
676             g_warning("Specified document %s cannot be opened (is it valid SVG file?)", (gchar *) fl->data);
677         } else {
678             if (sp_vacuum_defs) {
679                 vacuum_document(doc);
680             }
681             if (sp_vacuum_defs && !sp_export_svg) {
682                 // save under the name given in the command line
683                 sp_repr_save_file(doc->rdoc, (gchar *)fl->data, SP_SVG_NS_URI);
684             }
685             if (sp_global_printer) {
686                 sp_print_document_to_file(doc, sp_global_printer);
687             }
688             if (sp_export_png || sp_export_id || sp_export_area_drawing) {
689                 sp_do_export_png(doc);
690             }
691             if (sp_export_svg) {
692                 Inkscape::XML::Document *rdoc;
693                 Inkscape::XML::Node *repr;
694                 rdoc = sp_repr_document_new("svg:svg");
695                 repr = rdoc->root();
696                 repr = sp_document_root(doc)->updateRepr(repr, SP_OBJECT_WRITE_BUILD);
697                 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
698             }
699             if (sp_export_ps) {
700                 do_export_ps(doc, sp_export_ps, "image/x-postscript");
701             }
702             if (sp_export_eps) {
703                 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
704             }
705             if (sp_query_width || sp_query_height) {
706                 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
707             } else if (sp_query_x || sp_query_y) {
708                 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
709             }
710         }
711         fl = g_slist_remove(fl, fl->data);
712     }
714     inkscape_unref();
716     return 0;
719 static void
720 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
722     SPObject *o = NULL;
724     if (id) {
725         o = doc->getObjectById(id);
726         if (o) {
727             if (!SP_IS_ITEM (o)) {
728                 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
729                 return;
730             }
731         } else {
732             g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
733             return;
734         }
735     } else {
736         o = SP_DOCUMENT_ROOT(doc);
737     }
739     if (o) {
740         sp_document_ensure_up_to_date (doc);
741         SPItem *item = ((SPItem *) o);
742         NR::Rect area = item->invokeBbox(sp_item_i2doc_affine(item)); // "true" SVG bbox for scripting
744         Inkscape::SVGOStringStream os;
745         if (extent) {
746             os << area.extent(axis);
747         } else {
748             os << area.min()[axis];
749         }
750         g_print ("%s", os.str().c_str());
751     }
755 static void
756 sp_do_export_png(SPDocument *doc)
758     const gchar *filename = NULL;
759     gdouble dpi = 0.0;
761     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
762         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
763     }
765     GSList *items = NULL;
767     NRRect area;
768     if (sp_export_id || sp_export_area_drawing) {
770         SPObject *o = NULL;
771         if (sp_export_id) {
772             o = doc->getObjectById(sp_export_id);
773         } else if (sp_export_area_drawing) {
774             o = SP_DOCUMENT_ROOT (doc);
775         }
777         if (o) {
778             if (!SP_IS_ITEM (o)) {
779                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
780                 return;
781             }
782             if (sp_export_area) {
783                 g_warning ("Object with id=\"%s\" is being exported; --export-area is ignored.", sp_export_id);
784             }
786             items = g_slist_prepend (items, SP_ITEM(o));
788             if (sp_export_id_only) {
789                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
790             }
792             if (sp_export_use_hints) {
794                 // retrieve export filename hint
795                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
796                 if (fn_hint) {
797                     if (sp_export_png) {
798                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
799                         filename = sp_export_png;
800                     } else {
801                         filename = fn_hint;
802                     }
803                 } else {
804                     g_warning ("Export filename hint not found for the object.");
805                     filename = sp_export_png;
806                 }
808                 // retrieve export dpi hints
809                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
810                 if (dpi_hint) {
811                     if (sp_export_dpi || sp_export_width || sp_export_height) {
812                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
813                     } else {
814                         dpi = atof(dpi_hint);
815                     }
816                 } else {
817                     g_warning ("Export DPI hint not found for the object.");
818                 }
820             }
822             // write object bbox to area
823             sp_document_ensure_up_to_date (doc);
824             sp_item_invoke_bbox((SPItem *) o, &area, sp_item_i2r_affine((SPItem *) o), TRUE);
825         } else {
826             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
827             return;
828         }
829     } else if (sp_export_area) {
830         /* Try to parse area (given in SVG pixels) */
831         if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
832             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
833             return;
834         }
835         if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
836             g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
837             return;
838         }
839     } else {
840         /* Export the whole canvas */
841         sp_document_ensure_up_to_date (doc);
842         area.x0 = SP_ROOT(doc->root)->x.computed;
843         area.y0 = SP_ROOT(doc->root)->y.computed;
844         area.x1 = area.x0 + sp_document_width (doc);
845         area.y1 = area.y0 + sp_document_height (doc);
846     }
848     // set filename and dpi from options, if not yet set from the hints
849     if (!filename) {
850         if (!sp_export_png) {
851             g_warning ("No export filename given and no filename hint. Nothing exported.");
852             return;
853         }
854         filename = sp_export_png;
855     }
857     if (sp_export_dpi && dpi == 0.0) {
858         dpi = atof(sp_export_dpi);
859         if ((dpi < 0.1) || (dpi > 10000.0)) {
860             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
861             return;
862         }
863         g_print("DPI: %g\n", dpi);
864     }
866     if (sp_export_area_snap) {
867         area.x0 = std::floor (area.x0);
868         area.y0 = std::floor (area.y0);
869         area.x1 = std::ceil (area.x1);
870         area.y1 = std::ceil (area.y1);
871     }
873     // default dpi
874     if (dpi == 0.0)
875         dpi = PX_PER_IN;
877     gint width = 0;
878     gint height = 0;
880     if (sp_export_width) {
881         width = atoi(sp_export_width);
882         if ((width < 1) || (width > 65536)) {
883             g_warning("Export width %d out of range (1 - 65536). Nothing exported.", width);
884             return;
885         }
886         dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
887     }
889     if (sp_export_height) {
890         height = atoi(sp_export_height);
891         if ((height < 1) || (height > 65536)) {
892             g_warning("Export height %d out of range (1 - 65536). Nothing exported.", width);
893             return;
894         }
895         dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
896     }
898     if (!sp_export_width) {
899         width = (gint) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
900     }
902     if (!sp_export_height) {
903         height = (gint) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
904     }
906     guint32 bgcolor = 0x00000000;
907     if (sp_export_background) {
908         // override the page color
909         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
910         bgcolor |= 0xff; // default is no opacity
911     } else {
912         // read from namedview
913         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
914         if (nv && nv->attribute("pagecolor"))
915             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
916         if (nv && nv->attribute("inkscape:pageopacity"))
917             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
918     }
920     if (sp_export_background_opacity) {
921         // override opacity
922         gfloat value;
923         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
924             if (value > 1.0) {
925                 value = CLAMP (value, 1.0f, 255.0f);
926                 bgcolor &= (guint32) 0xffffff00;
927                 bgcolor |= (guint32) floor(value);
928             } else {
929                 value = CLAMP (value, 0.0f, 1.0f);
930                 bgcolor &= (guint32) 0xffffff00;
931                 bgcolor |= SP_COLOR_F_TO_U(value);
932             }
933         }
934     }
936     g_print("Background RRGGBBAA: %08x\n", bgcolor);
938     g_print("Area %g:%g:%g:%g exported to %d x %d pixels (%g dpi)\n", area.x0, area.y0, area.x1, area.y1, width, height, dpi);
940     g_print("Bitmap saved as: %s\n", filename);
942     if ((width >= 1) && (height >= 1) && (width < 65536) && (height < 65536)) {
943         sp_export_png_file(doc, filename, area.x0, area.y0, area.x1, area.y1, width, height, bgcolor, NULL, NULL, true, sp_export_id_only ? items : NULL);
944     } else {
945         g_warning("Calculated bitmap dimensions %d %d are out of range (1 - 65535). Nothing exported.", width, height);
946     }
948     g_slist_free (items);
952 /**
953  *  Perform an export of either PS or EPS.
954  *
955  *  \param doc Document to export.
956  *  \param uri URI to export to.
957  *  \param mime MIME type to export as.
958  */
960 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
962     /** \todo
963      * FIXME: I've no idea if this is the `proper' way to do this.
964      * If anyone feels qualified to say that it is, perhaps they
965      * could remove this comment.
966      */
968     Inkscape::Extension::DB::OutputList o;
969     Inkscape::Extension::db.get_output_list(o);
970     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
971     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
972         i++;
973     }
975     if (i == o.end())
976     {
977         g_warning ("Could not find an extension to export this file.");
978         return;
979     }
981     bool old_text_to_path = false;
982     bool old_bbox_page = false;
984     try {
985         old_text_to_path = (*i)->get_param_bool("textToPath");
986         (*i)->set_param_bool("textToPath", sp_export_text_to_path);
987     }
988     catch (...) {
989         g_warning ("Could not set export-text-to-path option for this export.");
990     }
992     try {
993         old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
994         (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
995     }
996     catch (...) {
997         g_warning ("Could not set export-bbox-page option for this export.");
998     }
1000     (*i)->save(doc, uri);
1002     try {
1003         (*i)->set_param_bool("textToPath", old_text_to_path);
1004         (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1005     }
1006     catch (...) {
1008     }
1011 #ifdef WIN32
1012 bool replaceArgs( int& argc, char**& argv )
1014     bool worked = false;
1016 #ifdef REPLACEARGS_DEBUG
1017     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1018 #endif // REPLACEARGS_DEBUG
1020     wchar_t* line = GetCommandLineW();
1021     if ( line )
1022     {
1023 #ifdef REPLACEARGS_DEBUG
1024         {
1025             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1026             if ( utf8Line )
1027             {
1028                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1029                 {
1030                     char tmp[strlen(safe) + 32];
1031                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1032                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1033                 }
1034             }
1035         }
1036 #endif // REPLACEARGS_DEBUG
1038         int numArgs = 0;
1039         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1041 #ifdef REPLACEARGS_ANSI
1042 // test code for trying things on Win95/98/ME
1043         if ( !parsed )
1044         {
1045 #ifdef REPLACEARGS_DEBUG
1046             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1047 #endif // REPLACEARGS_DEBUG
1048             int lineLen = wcslen(line) + 1;
1049             wchar_t* lineDup = new wchar_t[lineLen];
1050             wcsncpy( lineDup, line, lineLen );
1052             int pos = 0;
1053             bool inQuotes = false;
1054             bool inWhitespace = true;
1055             std::vector<int> places;
1056             while ( lineDup[pos] )
1057             {
1058                 if ( inQuotes )
1059                 {
1060                     if ( lineDup[pos] == L'"' )
1061                     {
1062                         inQuotes = false;
1063                     }
1064                 }
1065                 else if ( lineDup[pos] == L'"' )
1066                 {
1067                     inQuotes = true;
1068                     inWhitespace = false;
1069                     places.push_back(pos);
1070                 }
1071                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1072                 {
1073                     if ( !inWhitespace )
1074                     {
1075                         inWhitespace = true;
1076                         lineDup[pos] = 0;
1077                     }
1078                 }
1079                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1080                 {
1081                     inWhitespace = false;
1082                     places.push_back(pos);
1083                 }
1084                 else
1085                 {
1086                     // consume
1087                 }
1088                 pos++;
1089             }
1090 #ifdef REPLACEARGS_DEBUG
1091             {
1092                 char tmp[256];
1093                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1094                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1095             }
1096 #endif // REPLACEARGS_DEBUG
1098             wchar_t** block = new wchar_t*[places.size()];
1099             int i = 0;
1100             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1101             {
1102                 block[i++] = &lineDup[*it];
1103             }
1104             parsed = block;
1105             numArgs = places.size();
1106         }
1107 #endif // REPLACEARGS_ANSI
1109         if ( parsed )
1110         {
1111             std::vector<wchar_t*>expandedArgs;
1112             if ( numArgs > 0 )
1113             {
1114                 expandedArgs.push_back( parsed[0] );
1115             }
1117             for ( int i1 = 1; i1 < numArgs; i1++ )
1118             {
1119                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1120                 wildcarded &= parsed[i1][0] != L'"';
1121                 wildcarded &= parsed[i1][0] != L'-';
1122                 if ( wildcarded )
1123                 {
1124 #ifdef REPLACEARGS_ANSI
1125                     WIN32_FIND_DATAA data = {0};
1126 #else
1127                     WIN32_FIND_DATAW data = {0};
1128 #endif // REPLACEARGS_ANSI
1130                     int baseLen = wcslen(parsed[i1]) + 2;
1131                     wchar_t* base = new wchar_t[baseLen];
1132                     wcsncpy( base, parsed[i1], baseLen );
1133                     wchar_t* last = wcsrchr( base, L'\\' );
1134                     if ( last )
1135                     {
1136                         last[1] = 0;
1137                     }
1138                     else
1139                     {
1140                         base[0] = 0;
1141                     }
1142                     baseLen = wcslen( base );
1144 #ifdef REPLACEARGS_ANSI
1145                     char target[MAX_PATH];
1146                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1147                     {
1148                         HANDLE hf = FindFirstFileA( target, &data );
1149 #else
1150                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1151 #endif // REPLACEARGS_ANSI
1152                         if ( hf != INVALID_HANDLE_VALUE )
1153                         {
1154                             BOOL found = TRUE;
1155                             do
1156                             {
1157 #ifdef REPLACEARGS_ANSI
1158                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1159                                 if ( howMany > 0 )
1160                                 {
1161                                     howMany += baseLen;
1162                                     wchar_t* tmp = new wchar_t[howMany + 1];
1163                                     wcsncpy( tmp, base, howMany + 1 );
1164                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1165                                     expandedArgs.push_back( tmp );
1166                                     found = FindNextFileA( hf, &data );
1167                                 }
1168 #else
1169                                 int howMany = wcslen(data.cFileName) + baseLen;
1170                                 wchar_t* tmp = new wchar_t[howMany + 1];
1171                                 wcsncpy( tmp, base, howMany + 1 );
1172                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1173                                 expandedArgs.push_back( tmp );
1174                                 found = FindNextFileW( hf, &data );
1175 #endif // REPLACEARGS_ANSI
1176                             } while ( found );
1178                             FindClose( hf );
1179                         }
1180                         else
1181                         {
1182                             expandedArgs.push_back( parsed[i1] );
1183                         }
1184 #ifdef REPLACEARGS_ANSI
1185                     }
1186 #endif // REPLACEARGS_ANSI
1188                     delete[] base;
1189                 }
1190                 else
1191                 {
1192                     expandedArgs.push_back( parsed[i1] );
1193                 }
1194             }
1196             {
1197                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1198                 int iz = 0;
1199                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1200                 {
1201                     block[iz++] = *it;
1202                 }
1203                 parsed = block;
1204                 numArgs = expandedArgs.size();
1205             }
1207             std::vector<gchar*> newArgs;
1208             for ( int i = 0; i < numArgs; i++ )
1209             {
1210                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1211                 if ( replacement )
1212                 {
1213 #ifdef REPLACEARGS_DEBUG
1214                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1216                     if ( safe2 )
1217                     {
1218                         {
1219                             char tmp[1024];
1220                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1221                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1222                         }
1223                         g_free( safe2 );
1224                     }
1225 #endif // REPLACEARGS_DEBUG
1227                     newArgs.push_back( replacement );
1228                 }
1229                 else
1230                 {
1231                     newArgs.push_back( blankParam );
1232                 }
1233             }
1235             // Now push our munged params to be the new argv and argc
1236             {
1237                 char** block = new char*[newArgs.size()];
1238                 int iz = 0;
1239                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1240                 {
1241                     block[iz++] = *it;
1242                 }
1243                 argv = block;
1244                 argc = newArgs.size();
1245                 worked = true;
1246             }
1247         }
1248 #ifdef REPLACEARGS_DEBUG
1249         else
1250         {
1251             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1252         }
1253 #endif // REPLACEARGS_DEBUG
1254     }
1255 #ifdef REPLACEARGS_DEBUG
1256     else
1257     {
1258         {
1259             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1260         }
1262         char* line2 = GetCommandLineA();
1263         if ( line2 )
1264         {
1265             gchar *safe = Inkscape::IO::sanitizeString(line2);
1266             {
1267                 {
1268                     char tmp[strlen(safe) + 32];
1269                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1270                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1271                 }
1272             }
1273         }
1274         else
1275         {
1276             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1277         }
1278     }
1279 #endif // REPLACEARGS_DEBUG
1281     return worked;
1283 #endif // WIN32
1285 static GSList *
1286 sp_process_args(poptContext ctx)
1288     GSList *fl = NULL;
1290     gint a;
1291     while ((a = poptGetNextOpt(ctx)) >= 0) {
1292         switch (a) {
1293             case SP_ARG_FILE: {
1294                 gchar const *fn = poptGetOptArg(ctx);
1295                 if (fn != NULL) {
1296                     fl = g_slist_append(fl, g_strdup(fn));
1297                 }
1298                 break;
1299             }
1300             case SP_ARG_VERSION: {
1301                 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1302                 exit(0);
1303                 break;
1304             }
1305             case SP_ARG_EXTENSIONDIR: {
1306                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1307                 exit(0);
1308                 break;
1309             }
1310             default: {
1311                 break;
1312             }
1313         }
1314     }
1316     gchar const ** const args = poptGetArgs(ctx);
1317     if (args != NULL) {
1318         for (unsigned i = 0; args[i] != NULL; i++) {
1319             fl = g_slist_append(fl, g_strdup(args[i]));
1320         }
1321     }
1323     return fl;
1327 /*
1328   Local Variables:
1329   mode:c++
1330   c-file-style:"stroustrup"
1331   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1332   indent-tabs-mode:nil
1333   fill-column:99
1334   End:
1335 */
1336 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :