Code

Applying patch #1415498 by James Kilfiger / zeimusu - Allow color & transparency...
[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         NR::Rect area = sp_item_bbox_desktop((SPItem *) o);
743         Inkscape::SVGOStringStream os;
744         if (extent) {
745             os << area.extent(axis);
746         } else {
747             os << area.min()[axis];
748         }
749         g_print ("%s\n", os.str().c_str());
750     }
754 static void
755 sp_do_export_png(SPDocument *doc)
757     const gchar *filename = NULL;
758     gdouble dpi = 0.0;
760     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
761         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
762     }
764     GSList *items = NULL;
766     NRRect area;
767     if (sp_export_id || sp_export_area_drawing) {
769         SPObject *o = NULL;
770         if (sp_export_id) {
771             o = doc->getObjectById(sp_export_id);
772         } else if (sp_export_area_drawing) {
773             o = SP_DOCUMENT_ROOT (doc);
774         }
776         if (o) {
777             if (!SP_IS_ITEM (o)) {
778                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
779                 return;
780             }
781             if (sp_export_area) {
782                 g_warning ("Object with id=\"%s\" is being exported; --export-area is ignored.", sp_export_id);
783             }
785             items = g_slist_prepend (items, SP_ITEM(o));
787             if (sp_export_id_only) {
788                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
789             }
791             if (sp_export_use_hints) {
793                 // retrieve export filename hint
794                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
795                 if (fn_hint) {
796                     if (sp_export_png) {
797                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
798                         filename = sp_export_png;
799                     } else {
800                         filename = fn_hint;
801                     }
802                 } else {
803                     g_warning ("Export filename hint not found for the object.");
804                     filename = sp_export_png;
805                 }
807                 // retrieve export dpi hints
808                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
809                 if (dpi_hint) {
810                     if (sp_export_dpi || sp_export_width || sp_export_height) {
811                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
812                     } else {
813                         dpi = atof(dpi_hint);
814                     }
815                 } else {
816                     g_warning ("Export DPI hint not found for the object.");
817                 }
819             }
821             // write object bbox to area
822             sp_document_ensure_up_to_date (doc);
823             sp_item_invoke_bbox((SPItem *) o, &area, sp_item_i2r_affine((SPItem *) o), TRUE);
824         } else {
825             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
826             return;
827         }
828     } else if (sp_export_area) {
829         /* Try to parse area (given in SVG pixels) */
830         if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
831             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
832             return;
833         }
834         if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
835             g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
836             return;
837         }
838     } else {
839         /* Export the whole canvas */
840         sp_document_ensure_up_to_date (doc);
841         area.x0 = SP_ROOT(doc->root)->x.computed;
842         area.y0 = SP_ROOT(doc->root)->y.computed;
843         area.x1 = area.x0 + sp_document_width (doc);
844         area.y1 = area.y0 + sp_document_height (doc);
845     }
847     // set filename and dpi from options, if not yet set from the hints
848     if (!filename) {
849         if (!sp_export_png) {
850             g_warning ("No export filename given and no filename hint. Nothing exported.");
851             return;
852         }
853         filename = sp_export_png;
854     }
856     if (sp_export_dpi && dpi == 0.0) {
857         dpi = atof(sp_export_dpi);
858         if ((dpi < 0.1) || (dpi > 10000.0)) {
859             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
860             return;
861         }
862         g_print("DPI: %g\n", dpi);
863     }
865     if (sp_export_area_snap) {
866         area.x0 = std::floor (area.x0);
867         area.y0 = std::floor (area.y0);
868         area.x1 = std::ceil (area.x1);
869         area.y1 = std::ceil (area.y1);
870     }
872     // default dpi
873     if (dpi == 0.0)
874         dpi = PX_PER_IN;
876     gint width = 0;
877     gint height = 0;
879     if (sp_export_width) {
880         width = atoi(sp_export_width);
881         if ((width < 1) || (width > 65536)) {
882             g_warning("Export width %d out of range (1 - 65536). Nothing exported.", width);
883             return;
884         }
885         dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
886     }
888     if (sp_export_height) {
889         height = atoi(sp_export_height);
890         if ((height < 1) || (height > 65536)) {
891             g_warning("Export height %d out of range (1 - 65536). Nothing exported.", width);
892             return;
893         }
894         dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
895     }
897     if (!sp_export_width) {
898         width = (gint) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
899     }
901     if (!sp_export_height) {
902         height = (gint) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
903     }
905     guint32 bgcolor = 0x00000000;
906     if (sp_export_background) {
907         // override the page color
908         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
909         bgcolor |= 0xff; // default is no opacity
910     } else {
911         // read from namedview
912         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
913         if (nv && nv->attribute("pagecolor"))
914             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
915         if (nv && nv->attribute("inkscape:pageopacity"))
916             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
917     }
919     if (sp_export_background_opacity) {
920         // override opacity
921         gfloat value;
922         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
923             if (value > 1.0) {
924                 value = CLAMP (value, 1.0f, 255.0f);
925                 bgcolor &= (guint32) 0xffffff00;
926                 bgcolor |= (guint32) floor(value);
927             } else {
928                 value = CLAMP (value, 0.0f, 1.0f);
929                 bgcolor &= (guint32) 0xffffff00;
930                 bgcolor |= SP_COLOR_F_TO_U(value);
931             }
932         }
933     }
935     g_print("Background RRGGBBAA: %08x\n", bgcolor);
937     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);
939     g_print("Bitmap saved as: %s\n", filename);
941     if ((width >= 1) && (height >= 1) && (width < 65536) && (height < 65536)) {
942         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);
943     } else {
944         g_warning("Calculated bitmap dimensions %d %d are out of range (1 - 65535). Nothing exported.", width, height);
945     }
947     g_slist_free (items);
951 /**
952  *  Perform an export of either PS or EPS.
953  *
954  *  \param doc Document to export.
955  *  \param uri URI to export to.
956  *  \param mime MIME type to export as.
957  */
959 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
961     /** \todo
962      * FIXME: I've no idea if this is the `proper' way to do this.
963      * If anyone feels qualified to say that it is, perhaps they
964      * could remove this comment.
965      */
967     Inkscape::Extension::DB::OutputList o;
968     Inkscape::Extension::db.get_output_list(o);
969     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
970     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
971         i++;
972     }
974     if (i == o.end())
975     {
976         g_warning ("Could not find an extension to export this file.");
977         return;
978     }
980     bool old_text_to_path = false;
981     bool old_bbox_page = false;
983     try {
984         old_text_to_path = (*i)->get_param_bool("textToPath");
985         (*i)->set_param_bool("textToPath", sp_export_text_to_path);
986     }
987     catch (...) {
988         g_warning ("Could not set export-text-to-path option for this export.");
989     }
991     try {
992         old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
993         (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
994     }
995     catch (...) {
996         g_warning ("Could not set export-bbox-page option for this export.");
997     }
999     (*i)->save(doc, uri);
1001     try {
1002         (*i)->set_param_bool("textToPath", old_text_to_path);
1003         (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1004     }
1005     catch (...) {
1007     }
1010 #ifdef WIN32
1011 bool replaceArgs( int& argc, char**& argv )
1013     bool worked = false;
1015 #ifdef REPLACEARGS_DEBUG
1016     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1017 #endif // REPLACEARGS_DEBUG
1019     wchar_t* line = GetCommandLineW();
1020     if ( line )
1021     {
1022 #ifdef REPLACEARGS_DEBUG
1023         {
1024             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1025             if ( utf8Line )
1026             {
1027                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1028                 {
1029                     char tmp[strlen(safe) + 32];
1030                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1031                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1032                 }
1033             }
1034         }
1035 #endif // REPLACEARGS_DEBUG
1037         int numArgs = 0;
1038         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1040 #ifdef REPLACEARGS_ANSI
1041 // test code for trying things on Win95/98/ME
1042         if ( !parsed )
1043         {
1044 #ifdef REPLACEARGS_DEBUG
1045             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1046 #endif // REPLACEARGS_DEBUG
1047             int lineLen = wcslen(line) + 1;
1048             wchar_t* lineDup = new wchar_t[lineLen];
1049             wcsncpy( lineDup, line, lineLen );
1051             int pos = 0;
1052             bool inQuotes = false;
1053             bool inWhitespace = true;
1054             std::vector<int> places;
1055             while ( lineDup[pos] )
1056             {
1057                 if ( inQuotes )
1058                 {
1059                     if ( lineDup[pos] == L'"' )
1060                     {
1061                         inQuotes = false;
1062                     }
1063                 }
1064                 else if ( lineDup[pos] == L'"' )
1065                 {
1066                     inQuotes = true;
1067                     inWhitespace = false;
1068                     places.push_back(pos);
1069                 }
1070                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1071                 {
1072                     if ( !inWhitespace )
1073                     {
1074                         inWhitespace = true;
1075                         lineDup[pos] = 0;
1076                     }
1077                 }
1078                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1079                 {
1080                     inWhitespace = false;
1081                     places.push_back(pos);
1082                 }
1083                 else
1084                 {
1085                     // consume
1086                 }
1087                 pos++;
1088             }
1089 #ifdef REPLACEARGS_DEBUG
1090             {
1091                 char tmp[256];
1092                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1093                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1094             }
1095 #endif // REPLACEARGS_DEBUG
1097             wchar_t** block = new wchar_t*[places.size()];
1098             int i = 0;
1099             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1100             {
1101                 block[i++] = &lineDup[*it];
1102             }
1103             parsed = block;
1104             numArgs = places.size();
1105         }
1106 #endif // REPLACEARGS_ANSI
1108         if ( parsed )
1109         {
1110             std::vector<wchar_t*>expandedArgs;
1111             if ( numArgs > 0 )
1112             {
1113                 expandedArgs.push_back( parsed[0] );
1114             }
1116             for ( int i1 = 1; i1 < numArgs; i1++ )
1117             {
1118                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1119                 wildcarded &= parsed[i1][0] != L'"';
1120                 wildcarded &= parsed[i1][0] != L'-';
1121                 if ( wildcarded )
1122                 {
1123 #ifdef REPLACEARGS_ANSI
1124                     WIN32_FIND_DATAA data = {0};
1125 #else
1126                     WIN32_FIND_DATAW data = {0};
1127 #endif // REPLACEARGS_ANSI
1129                     int baseLen = wcslen(parsed[i1]) + 2;
1130                     wchar_t* base = new wchar_t[baseLen];
1131                     wcsncpy( base, parsed[i1], baseLen );
1132                     wchar_t* last = wcsrchr( base, L'\\' );
1133                     if ( last )
1134                     {
1135                         last[1] = 0;
1136                     }
1137                     else
1138                     {
1139                         base[0] = 0;
1140                     }
1141                     baseLen = wcslen( base );
1143 #ifdef REPLACEARGS_ANSI
1144                     char target[MAX_PATH];
1145                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1146                     {
1147                         HANDLE hf = FindFirstFileA( target, &data );
1148 #else
1149                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1150 #endif // REPLACEARGS_ANSI
1151                         if ( hf != INVALID_HANDLE_VALUE )
1152                         {
1153                             BOOL found = TRUE;
1154                             do
1155                             {
1156 #ifdef REPLACEARGS_ANSI
1157                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1158                                 if ( howMany > 0 )
1159                                 {
1160                                     howMany += baseLen;
1161                                     wchar_t* tmp = new wchar_t[howMany + 1];
1162                                     wcsncpy( tmp, base, howMany + 1 );
1163                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1164                                     expandedArgs.push_back( tmp );
1165                                     found = FindNextFileA( hf, &data );
1166                                 }
1167 #else
1168                                 int howMany = wcslen(data.cFileName) + baseLen;
1169                                 wchar_t* tmp = new wchar_t[howMany + 1];
1170                                 wcsncpy( tmp, base, howMany + 1 );
1171                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1172                                 expandedArgs.push_back( tmp );
1173                                 found = FindNextFileW( hf, &data );
1174 #endif // REPLACEARGS_ANSI
1175                             } while ( found );
1177                             FindClose( hf );
1178                         }
1179                         else
1180                         {
1181                             expandedArgs.push_back( parsed[i1] );
1182                         }
1183 #ifdef REPLACEARGS_ANSI
1184                     }
1185 #endif // REPLACEARGS_ANSI
1187                     delete[] base;
1188                 }
1189                 else
1190                 {
1191                     expandedArgs.push_back( parsed[i1] );
1192                 }
1193             }
1195             {
1196                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1197                 int iz = 0;
1198                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1199                 {
1200                     block[iz++] = *it;
1201                 }
1202                 parsed = block;
1203                 numArgs = expandedArgs.size();
1204             }
1206             std::vector<gchar*> newArgs;
1207             for ( int i = 0; i < numArgs; i++ )
1208             {
1209                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1210                 if ( replacement )
1211                 {
1212 #ifdef REPLACEARGS_DEBUG
1213                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1215                     if ( safe2 )
1216                     {
1217                         {
1218                             char tmp[1024];
1219                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1220                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1221                         }
1222                         g_free( safe2 );
1223                     }
1224 #endif // REPLACEARGS_DEBUG
1226                     newArgs.push_back( replacement );
1227                 }
1228                 else
1229                 {
1230                     newArgs.push_back( blankParam );
1231                 }
1232             }
1234             // Now push our munged params to be the new argv and argc
1235             {
1236                 char** block = new char*[newArgs.size()];
1237                 int iz = 0;
1238                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1239                 {
1240                     block[iz++] = *it;
1241                 }
1242                 argv = block;
1243                 argc = newArgs.size();
1244                 worked = true;
1245             }
1246         }
1247 #ifdef REPLACEARGS_DEBUG
1248         else
1249         {
1250             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1251         }
1252 #endif // REPLACEARGS_DEBUG
1253     }
1254 #ifdef REPLACEARGS_DEBUG
1255     else
1256     {
1257         {
1258             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1259         }
1261         char* line2 = GetCommandLineA();
1262         if ( line2 )
1263         {
1264             gchar *safe = Inkscape::IO::sanitizeString(line2);
1265             {
1266                 {
1267                     char tmp[strlen(safe) + 32];
1268                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1269                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1270                 }
1271             }
1272         }
1273         else
1274         {
1275             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1276         }
1277     }
1278 #endif // REPLACEARGS_DEBUG
1280     return worked;
1282 #endif // WIN32
1284 static GSList *
1285 sp_process_args(poptContext ctx)
1287     GSList *fl = NULL;
1289     gint a;
1290     while ((a = poptGetNextOpt(ctx)) >= 0) {
1291         switch (a) {
1292             case SP_ARG_FILE: {
1293                 gchar const *fn = poptGetOptArg(ctx);
1294                 if (fn != NULL) {
1295                     fl = g_slist_append(fl, g_strdup(fn));
1296                 }
1297                 break;
1298             }
1299             case SP_ARG_VERSION: {
1300                 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1301                 exit(0);
1302                 break;
1303             }
1304             case SP_ARG_EXTENSIONDIR: {
1305                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1306                 exit(0);
1307                 break;
1308             }
1309             default: {
1310                 break;
1311             }
1312         }
1313     }
1315     gchar const ** const args = poptGetArgs(ctx);
1316     if (args != NULL) {
1317         for (unsigned i = 0; args[i] != NULL; i++) {
1318             fl = g_slist_append(fl, g_strdup(args[i]));
1319         }
1320     }
1322     return fl;
1326 /*
1327   Local Variables:
1328   mode:c++
1329   c-file-style:"stroustrup"
1330   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1331   indent-tabs-mode:nil
1332   fill-column:99
1333   End:
1334 */
1335 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :