df62e8d0dbdf62d274d228d4d8ec40951e91dd8c
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 <cstring>
37 #include <string>
38 #include <locale.h>
40 #include <popt.h>
41 #ifndef POPT_TABLEEND
42 #define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
43 #endif /* Not def: POPT_TABLEEND */
45 #include <libxml/tree.h>
46 #include <glib-object.h>
47 #include <gtk/gtkmain.h>
48 #include <gtk/gtksignal.h>
49 #include <gtk/gtkwindow.h>
50 #include <gtk/gtkbox.h>
52 #include "gc-core.h"
54 #include "macros.h"
55 #include "file.h"
56 #include "document.h"
57 #include "sp-object.h"
58 #include "interface.h"
59 #include "print.h"
60 #include "color.h"
61 #include "sp-item.h"
62 #include "sp-root.h"
63 #include "unit-constants.h"
65 #include "svg/svg.h"
66 #include "svg/svg-color.h"
67 #include "svg/stringstream.h"
69 #include "inkscape-private.h"
70 #include "inkscape-stock.h"
71 #include "inkscape_version.h"
73 #include "sp-namedview.h"
74 #include "sp-guide.h"
75 #include "sp-object-repr.h"
76 #include "xml/repr.h"
78 #include "io/sys.h"
80 #include "debug/logger.h"
81 #include "debug/log-display-config.h"
83 #include "helper/png-write.h"
85 #include <extension/extension.h>
86 #include <extension/system.h>
87 #include <extension/db.h>
88 #include <extension/output.h>
90 #ifdef WIN32
91 //#define REPLACEARGS_ANSI
92 //#define REPLACEARGS_DEBUG
94 #include "registrytool.h"
96 #include "extension/internal/win32.h"
97 using Inkscape::Extension::Internal::PrintWin32;
99 #endif // WIN32
101 #include "extension/init.h"
103 #include <glibmm/i18n.h>
104 #include <gtkmm/main.h>
106 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
107 #define bind_textdomain_codeset(p,c)
108 #endif
110 #include "application/application.h"
112 #include "main-cmdlineact.h"
114 #include <png.h>
115 #include <errno.h>
117 enum {
118 SP_ARG_NONE,
119 SP_ARG_NOGUI,
120 SP_ARG_GUI,
121 SP_ARG_FILE,
122 SP_ARG_PRINT,
123 SP_ARG_EXPORT_PNG,
124 SP_ARG_EXPORT_DPI,
125 SP_ARG_EXPORT_AREA,
126 SP_ARG_EXPORT_AREA_DRAWING,
127 SP_ARG_EXPORT_AREA_CANVAS,
128 SP_ARG_EXPORT_AREA_SNAP,
129 SP_ARG_EXPORT_WIDTH,
130 SP_ARG_EXPORT_HEIGHT,
131 SP_ARG_EXPORT_ID,
132 SP_ARG_EXPORT_ID_ONLY,
133 SP_ARG_EXPORT_USE_HINTS,
134 SP_ARG_EXPORT_BACKGROUND,
135 SP_ARG_EXPORT_BACKGROUND_OPACITY,
136 SP_ARG_EXPORT_SVG,
137 SP_ARG_EXPORT_PS,
138 SP_ARG_EXPORT_EPS,
139 SP_ARG_EXPORT_PDF,
140 #ifdef WIN32
141 SP_ARG_EXPORT_EMF,
142 #endif //WIN32
143 SP_ARG_EXPORT_TEXT_TO_PATH,
144 SP_ARG_EXPORT_FONT,
145 SP_ARG_EXPORT_BBOX_PAGE,
146 SP_ARG_EXTENSIONDIR,
147 SP_ARG_FIT_PAGE_TO_DRAWING,
148 SP_ARG_QUERY_X,
149 SP_ARG_QUERY_Y,
150 SP_ARG_QUERY_WIDTH,
151 SP_ARG_QUERY_HEIGHT,
152 SP_ARG_QUERY_ALL,
153 SP_ARG_QUERY_ID,
154 SP_ARG_VERSION,
155 SP_ARG_VACUUM_DEFS,
156 SP_ARG_VERB_LIST,
157 SP_ARG_VERB,
158 SP_ARG_SELECT,
159 SP_ARG_LAST
160 };
162 int sp_main_gui(int argc, char const **argv);
163 int sp_main_console(int argc, char const **argv);
164 static void sp_do_export_png(SPDocument *doc);
165 static void do_export_ps(SPDocument* doc, gchar const* uri, char const *mime);
166 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const *mime);
167 #ifdef WIN32
168 static void do_export_emf(SPDocument* doc, gchar const* uri, char const *mime);
169 #endif //WIN32
170 static void do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id);
171 static void do_query_all (SPDocument *doc);
172 static void do_query_all_recurse (SPObject *o);
174 static gchar *sp_global_printer = NULL;
175 static gchar *sp_export_png = NULL;
176 static gchar *sp_export_dpi = NULL;
177 static gchar *sp_export_area = NULL;
178 static gboolean sp_export_area_drawing = FALSE;
179 static gboolean sp_export_area_canvas = FALSE;
180 static gchar *sp_export_width = NULL;
181 static gchar *sp_export_height = NULL;
182 static gchar *sp_export_id = NULL;
183 static gchar *sp_export_background = NULL;
184 static gchar *sp_export_background_opacity = NULL;
185 static gboolean sp_export_area_snap = FALSE;
186 static gboolean sp_export_use_hints = FALSE;
187 static gboolean sp_export_id_only = FALSE;
188 static gchar *sp_export_svg = NULL;
189 static gchar *sp_export_ps = NULL;
190 static gchar *sp_export_eps = NULL;
191 static gchar *sp_export_pdf = NULL;
192 #ifdef WIN32
193 static gchar *sp_export_emf = NULL;
194 #endif //WIN32
195 static gboolean sp_export_text_to_path = FALSE;
196 static gboolean sp_export_font = FALSE;
197 static gboolean sp_export_bbox_page = FALSE;
198 static gboolean sp_query_x = FALSE;
199 static gboolean sp_query_y = FALSE;
200 static gboolean sp_query_width = FALSE;
201 static gboolean sp_query_height = FALSE;
202 static gboolean sp_query_all = FALSE;
203 static gchar *sp_query_id = NULL;
204 static int sp_new_gui = FALSE;
205 static gboolean sp_vacuum_defs = FALSE;
207 static gchar *sp_export_png_utf8 = NULL;
208 static gchar *sp_export_svg_utf8 = NULL;
209 static gchar *sp_global_printer_utf8 = NULL;
211 #ifdef WIN32
212 static bool replaceArgs( int& argc, char**& argv );
213 #endif
214 static GSList *sp_process_args(poptContext ctx);
215 struct poptOption options[] = {
216 {"version", 'V',
217 POPT_ARG_NONE, NULL, SP_ARG_VERSION,
218 N_("Print the Inkscape version number"),
219 NULL},
221 {"without-gui", 'z',
222 POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
223 N_("Do not use X server (only process files from console)"),
224 NULL},
226 {"with-gui", 'g',
227 POPT_ARG_NONE, NULL, SP_ARG_GUI,
228 N_("Try to use X server (even if $DISPLAY is not set)"),
229 NULL},
231 {"file", 'f',
232 POPT_ARG_STRING, NULL, SP_ARG_FILE,
233 N_("Open specified document(s) (option string may be excluded)"),
234 N_("FILENAME")},
236 {"print", 'p',
237 POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
238 N_("Print document(s) to specified output file (use '| program' for pipe)"),
239 N_("FILENAME")},
241 {"export-png", 'e',
242 POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
243 N_("Export document to a PNG file"),
244 N_("FILENAME")},
246 {"export-dpi", 'd',
247 POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
248 N_("The resolution used for exporting SVG into bitmap (default 90)"),
249 N_("DPI")},
251 {"export-area", 'a',
252 POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
253 N_("Exported area in SVG user units (default is the canvas; 0,0 is lower-left corner)"),
254 N_("x0:y0:x1:y1")},
256 {"export-area-drawing", 'D',
257 POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
258 N_("Exported area is the entire drawing (not canvas)"),
259 NULL},
261 {"export-area-canvas", 'C',
262 POPT_ARG_NONE, &sp_export_area_canvas, SP_ARG_EXPORT_AREA_CANVAS,
263 N_("Exported area is the entire canvas"),
264 NULL},
266 {"export-area-snap", 0,
267 POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
268 N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
269 NULL},
271 {"export-width", 'w',
272 POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
273 N_("The width of exported bitmap in pixels (overrides export-dpi)"),
274 N_("WIDTH")},
276 {"export-height", 'h',
277 POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
278 N_("The height of exported bitmap in pixels (overrides export-dpi)"),
279 N_("HEIGHT")},
281 {"export-id", 'i',
282 POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
283 N_("The ID of the object to export"),
284 N_("ID")},
286 {"export-id-only", 'j',
287 POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
288 // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
289 // See "man inkscape" for details.
290 N_("Export just the object with export-id, hide all others (only with export-id)"),
291 NULL},
293 {"export-use-hints", 't',
294 POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
295 N_("Use stored filename and DPI hints when exporting (only with export-id)"),
296 NULL},
298 {"export-background", 'b',
299 POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
300 N_("Background color of exported bitmap (any SVG-supported color string)"),
301 N_("COLOR")},
303 {"export-background-opacity", 'y',
304 POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
305 N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
306 N_("VALUE")},
308 {"export-plain-svg", 'l',
309 POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
310 N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
311 N_("FILENAME")},
313 {"export-ps", 'P',
314 POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
315 N_("Export document to a PS file"),
316 N_("FILENAME")},
318 {"export-eps", 'E',
319 POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
320 N_("Export document to an EPS file"),
321 N_("FILENAME")},
323 {"export-pdf", 'A',
324 POPT_ARG_STRING, &sp_export_pdf, SP_ARG_EXPORT_PDF,
325 N_("Export document to a PDF file"),
326 N_("FILENAME")},
328 #ifdef WIN32
329 {"export-emf", 'M',
330 POPT_ARG_STRING, &sp_export_emf, SP_ARG_EXPORT_EMF,
331 N_("Export document to an Enhanced Metafile (EMF) File"),
332 N_("FILENAME")},
333 #endif //WIN32
335 {"export-text-to-path", 'T',
336 POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
337 N_("Convert text object to paths on export (EPS)"),
338 NULL},
340 {"export-embed-fonts", 'F',
341 POPT_ARG_NONE, &sp_export_font, SP_ARG_EXPORT_FONT,
342 N_("Embed fonts on export (Type 1 only) (EPS)"),
343 NULL},
345 {"export-bbox-page", 'B',
346 POPT_ARG_NONE, &sp_export_bbox_page, SP_ARG_EXPORT_BBOX_PAGE,
347 N_("Export files with the bounding box set to the page size (EPS)"),
348 NULL},
350 {"query-x", 'X',
351 POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
352 // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
353 N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
354 NULL},
356 {"query-y", 'Y',
357 POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
358 // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
359 N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
360 NULL},
362 {"query-width", 'W',
363 POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
364 // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
365 N_("Query the width of the drawing or, if specified, of the object with --query-id"),
366 NULL},
368 {"query-height", 'H',
369 POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
370 // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
371 N_("Query the height of the drawing or, if specified, of the object with --query-id"),
372 NULL},
374 {"query-all", 'S',
375 POPT_ARG_NONE, &sp_query_all, SP_ARG_QUERY_ALL,
376 N_("List id,x,y,w,h for all objects"),
377 NULL},
379 {"query-id", 'I',
380 POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
381 N_("The ID of the object whose dimensions are queried"),
382 N_("ID")},
384 {"extension-directory", 'x',
385 POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
386 // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
387 N_("Print out the extension directory and exit"),
388 NULL},
390 {"vacuum-defs", 0,
391 POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
392 N_("Remove unused definitions from the defs section(s) of the document"),
393 NULL},
395 {"verb-list", 0,
396 POPT_ARG_NONE, NULL, SP_ARG_VERB_LIST,
397 N_("List the IDs of all the verbs in Inkscape"),
398 NULL},
400 {"verb", 0,
401 POPT_ARG_STRING, NULL, SP_ARG_VERB,
402 N_("Verb to call when Inkscape opens."),
403 N_("VERB-ID")},
405 {"select", 0,
406 POPT_ARG_STRING, NULL, SP_ARG_SELECT,
407 N_("Object ID to select when Inkscape opens."),
408 N_("OBJECT-ID")},
410 POPT_AUTOHELP POPT_TABLEEND
411 };
413 static bool needToRecodeParams = true;
414 gchar* blankParam = "";
416 int
417 main(int argc, char **argv)
418 {
419 #ifdef HAVE_FPSETMASK
420 /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__. It's probably
421 safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
422 the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
423 fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
424 #endif
426 #ifdef ENABLE_NLS
427 #ifdef WIN32
428 RegistryTool rt;
429 rt.setPathInfo();
430 gchar *pathBuf = g_strconcat(g_path_get_dirname(argv[0]), "\\", PACKAGE_LOCALE_DIR, NULL);
431 bindtextdomain(GETTEXT_PACKAGE, pathBuf);
432 g_free(pathBuf);
433 #else
434 #ifdef ENABLE_BINRELOC
435 bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
436 #else
437 bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
438 #endif
439 #endif
440 // Allow the user to override the locale directory by setting
441 // the environment variable INKSCAPE_LOCALEDIR.
442 char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR");
443 if (inkscape_localedir != NULL) {
444 bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
445 }
446 #endif
448 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
450 #ifdef ENABLE_NLS
451 textdomain(GETTEXT_PACKAGE);
452 #endif
454 LIBXML_TEST_VERSION
456 Inkscape::GC::init();
458 Inkscape::Debug::Logger::init();
460 gboolean use_gui;
461 #ifndef WIN32
462 use_gui = (getenv("DISPLAY") != NULL);
463 #else
464 /*
465 Set the current directory to the directory of the
466 executable. This seems redundant, but is needed for
467 when inkscape.exe is executed from another directory.
468 We use relative paths on win32.
469 HKCR\svgfile\shell\open\command is a good example
470 */
471 /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
472 char *homedir = g_path_get_dirname(argv[0]);
473 SetCurrentDirectory(homedir);
474 g_free(homedir);
476 use_gui = TRUE;
477 #endif
478 /* Test whether with/without GUI is forced */
479 for (int i = 1; i < argc; i++) {
480 if (!strcmp(argv[i], "-z")
481 || !strcmp(argv[i], "--without-gui")
482 || !strcmp(argv[i], "-p")
483 || !strncmp(argv[i], "--print", 7)
484 || !strcmp(argv[i], "-e")
485 || !strncmp(argv[i], "--export-png", 12)
486 || !strcmp(argv[i], "-l")
487 || !strncmp(argv[i], "--export-plain-svg", 12)
488 || !strcmp(argv[i], "-i")
489 || !strncmp(argv[i], "--export-area-drawing", 21)
490 || !strcmp(argv[i], "-D")
491 || !strncmp(argv[i], "--export-area-canvas", 20)
492 || !strcmp(argv[i], "-C")
493 || !strncmp(argv[i], "--export-id", 12)
494 || !strcmp(argv[i], "-P")
495 || !strncmp(argv[i], "--export-ps", 11)
496 || !strcmp(argv[i], "-E")
497 || !strncmp(argv[i], "--export-eps", 12)
498 || !strcmp(argv[i], "-A")
499 || !strncmp(argv[i], "--export-pdf", 12)
500 #ifdef WIN32
501 || !strcmp(argv[i], "-M")
502 || !strncmp(argv[i], "--export-emf", 12)
503 #endif //WIN32
504 || !strcmp(argv[i], "-W")
505 || !strncmp(argv[i], "--query-width", 13)
506 || !strcmp(argv[i], "-H")
507 || !strncmp(argv[i], "--query-height", 14)
508 || !strcmp(argv[i], "-S")
509 || !strncmp(argv[i], "--query-all", 11)
510 || !strcmp(argv[i], "-X")
511 || !strncmp(argv[i], "--query-x", 13)
512 || !strcmp(argv[i], "-Y")
513 || !strncmp(argv[i], "--query-y", 14)
514 || !strcmp(argv[i], "--vacuum-defs")
515 )
516 {
517 /* main_console handles any exports -- not the gui */
518 use_gui = FALSE;
519 break;
520 } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
521 use_gui = TRUE;
522 break;
523 }
524 }
526 #ifdef WIN32
527 #ifndef REPLACEARGS_ANSI
528 if ( PrintWin32::is_os_wide() )
529 #endif // REPLACEARGS_ANSI
530 {
531 // If the call fails, we'll need to convert charsets
532 needToRecodeParams = !replaceArgs( argc, argv );
533 }
534 #endif // WIN32
536 /// \todo Should this be a static object (see inkscape.cpp)?
537 Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
539 return app.run();
540 }
542 void fixupSingleFilename( gchar **orig, gchar **spare )
543 {
544 if ( orig && *orig && **orig ) {
545 GError *error = NULL;
546 gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
547 if ( newFileName )
548 {
549 *orig = newFileName;
550 if ( spare ) {
551 *spare = newFileName;
552 }
553 // g_message("Set a replacement fixup");
554 }
555 }
556 }
558 GSList *fixupFilenameEncoding( GSList* fl )
559 {
560 GSList *newFl = NULL;
561 while ( fl ) {
562 gchar *fn = static_cast<gchar*>(fl->data);
563 fl = g_slist_remove( fl, fl->data );
564 gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
565 if ( newFileName ) {
567 if ( 0 )
568 {
569 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
570 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
571 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
572 "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
573 gtk_dialog_run (GTK_DIALOG (w));
574 gtk_widget_destroy (w);
575 g_free(safeNewFn);
576 g_free(safeFn);
577 }
579 g_free( fn );
580 fn = newFileName;
581 newFileName = 0;
582 }
583 else
584 if ( 0 )
585 {
586 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
587 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
588 gtk_dialog_run (GTK_DIALOG (w));
589 gtk_widget_destroy (w);
590 g_free(safeFn);
591 }
592 newFl = g_slist_append( newFl, fn );
593 }
594 return newFl;
595 }
597 int sp_common_main( int argc, char const **argv, GSList **flDest )
598 {
599 /// \todo fixme: Move these to some centralized location (Lauris)
600 sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
601 sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
604 // temporarily switch gettext encoding to locale, so that help messages can be output properly
605 gchar const *charset;
606 g_get_charset(&charset);
608 bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
610 poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
611 poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
612 g_return_val_if_fail(ctx != NULL, 1);
614 /* Collect own arguments */
615 GSList *fl = sp_process_args(ctx);
616 poptFreeContext(ctx);
618 // now switch gettext back to UTF-8 (for GUI)
619 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
621 // Now let's see if the file list still holds up
622 if ( needToRecodeParams )
623 {
624 fl = fixupFilenameEncoding( fl );
625 }
627 // Check the globals for filename-fixup
628 if ( needToRecodeParams )
629 {
630 fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
631 fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
632 fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
633 }
634 else
635 {
636 if ( sp_export_png )
637 sp_export_png_utf8 = g_strdup( sp_export_png );
638 if ( sp_export_svg )
639 sp_export_svg_utf8 = g_strdup( sp_export_svg );
640 if ( sp_global_printer )
641 sp_global_printer_utf8 = g_strdup( sp_global_printer );
642 }
644 // Return the list if wanted, else free it up.
645 if ( flDest ) {
646 *flDest = fl;
647 fl = 0;
648 } else {
649 while ( fl ) {
650 g_free( fl->data );
651 fl = g_slist_remove( fl, fl->data );
652 }
653 }
654 return 0;
655 }
657 static void
658 snooper(GdkEvent *event, gpointer /*data*/) {
659 if(inkscape_mapalt()) /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
660 {
661 GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
662 switch (event->type) {
663 case GDK_MOTION_NOTIFY:
664 if(event->motion.state & mapping) {
665 event->motion.state|=GDK_MOD1_MASK;
666 }
667 break;
668 case GDK_BUTTON_PRESS:
669 if(event->button.state & mapping) {
670 event->button.state|=GDK_MOD1_MASK;
671 }
672 break;
673 case GDK_KEY_PRESS:
674 if(event->key.state & mapping) {
675 event->key.state|=GDK_MOD1_MASK;
676 }
677 break;
678 default:
679 break;
680 }
681 }
682 gtk_main_do_event (event);
683 }
685 int
686 sp_main_gui(int argc, char const **argv)
687 {
688 Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
690 GSList *fl = NULL;
691 int retVal = sp_common_main( argc, argv, &fl );
692 g_return_val_if_fail(retVal == 0, 1);
694 inkscape_gtk_stock_init();
696 gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
698 Inkscape::Debug::log_display_config();
700 /* Set default icon */
701 gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
702 if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
703 gtk_window_set_default_icon_from_file(filename, NULL);
704 }
705 g_free (filename);
706 filename = 0;
708 gboolean create_new = TRUE;
710 /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
711 inkscape_application_init(argv[0], true);
713 while (fl) {
714 if (sp_file_open((gchar *)fl->data,NULL)) {
715 create_new=FALSE;
716 }
717 fl = g_slist_remove(fl, fl->data);
718 }
719 if (create_new) {
720 sp_file_new_default();
721 }
723 Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
724 main_instance.run();
726 #ifdef WIN32
727 //We might not need anything here
728 //sp_win32_finish(); <-- this is a NOP func
729 #endif
731 return 0;
732 }
734 int
735 sp_main_console(int argc, char const **argv)
736 {
737 /* We are started in text mode */
739 /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
740 * in a non-Gtk environment. Used in libnrtype's
741 * FontInstance.cpp and FontFactory.cpp.
742 * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
743 */
744 g_type_init();
745 char **argv2 = const_cast<char **>(argv);
746 gtk_init_check( &argc, &argv2 );
747 //setlocale(LC_ALL, "");
749 GSList *fl = NULL;
750 int retVal = sp_common_main( argc, argv, &fl );
751 g_return_val_if_fail(retVal == 0, 1);
753 if (fl == NULL) {
754 g_print("Nothing to do!\n");
755 exit(0);
756 }
758 inkscape_application_init(argv[0], false);
760 while (fl) {
761 SPDocument *doc;
763 doc = Inkscape::Extension::open(NULL, (gchar *)fl->data);
764 if (doc == NULL) {
765 doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), (gchar *)fl->data);
766 }
767 if (doc == NULL) {
768 g_warning("Specified document %s cannot be opened (is it valid SVG file?)", (gchar *) fl->data);
769 } else {
770 if (sp_vacuum_defs) {
771 vacuum_document(doc);
772 }
773 if (sp_vacuum_defs && !sp_export_svg) {
774 // save under the name given in the command line
775 sp_repr_save_file(doc->rdoc, (gchar *)fl->data, SP_SVG_NS_URI);
776 }
777 if (sp_global_printer) {
778 sp_print_document_to_file(doc, sp_global_printer);
779 }
780 if (sp_export_png) {
781 sp_do_export_png(doc);
782 }
783 if (sp_export_svg) {
784 Inkscape::XML::Document *rdoc;
785 Inkscape::XML::Node *repr;
786 rdoc = sp_repr_document_new("svg:svg");
787 repr = rdoc->root();
788 repr = sp_document_root(doc)->updateRepr(repr, SP_OBJECT_WRITE_BUILD);
789 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
790 }
791 if (sp_export_ps) {
792 do_export_ps(doc, sp_export_ps, "image/x-postscript");
793 }
794 if (sp_export_eps) {
795 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
796 }
797 if (sp_export_pdf) {
798 do_export_pdf(doc, sp_export_pdf, "application/pdf");
799 }
800 #ifdef WIN32
801 if (sp_export_emf) {
802 do_export_emf(doc, sp_export_emf, "image/x-emf");
803 }
804 #endif //WIN32
805 if (sp_query_all) {
806 do_query_all (doc);
807 } else if (sp_query_width || sp_query_height) {
808 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
809 } else if (sp_query_x || sp_query_y) {
810 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
811 }
812 }
814 fl = g_slist_remove(fl, fl->data);
815 }
817 inkscape_unref();
819 return 0;
820 }
822 static void
823 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
824 {
825 SPObject *o = NULL;
827 if (id) {
828 o = doc->getObjectById(id);
829 if (o) {
830 if (!SP_IS_ITEM (o)) {
831 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
832 return;
833 }
834 } else {
835 g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
836 return;
837 }
838 } else {
839 o = SP_DOCUMENT_ROOT(doc);
840 }
842 if (o) {
843 sp_document_ensure_up_to_date (doc);
844 SPItem *item = ((SPItem *) o);
846 // "true" SVG bbox for scripting
847 NR::Maybe<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
848 if (area) {
849 Inkscape::SVGOStringStream os;
850 if (extent) {
851 os << area->extent(axis);
852 } else {
853 os << area->min()[axis];
854 }
855 g_print ("%s", os.str().c_str());
856 } else {
857 g_print("0");
858 }
859 }
860 }
862 static void
863 do_query_all (SPDocument *doc)
864 {
865 SPObject *o = NULL;
867 o = SP_DOCUMENT_ROOT(doc);
869 if (o) {
870 sp_document_ensure_up_to_date (doc);
871 do_query_all_recurse(o);
872 }
873 }
875 static void
876 do_query_all_recurse (SPObject *o)
877 {
878 SPItem *item = ((SPItem *) o);
879 if (o->id && SP_IS_ITEM(item)) {
880 NR::Maybe<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
881 if (area) {
882 Inkscape::SVGOStringStream os;
883 os << o->id;
884 os << "," << area->min()[NR::X];
885 os << "," << area->min()[NR::Y];
886 os << "," << area->extent(NR::X);
887 os << "," << area->extent(NR::Y);
888 g_print ("%s\n", os.str().c_str());
889 }
890 }
892 SPObject *child = o->children;
893 while (child) {
894 do_query_all_recurse (child);
895 child = child->next;
896 }
897 }
900 static void
901 sp_do_export_png(SPDocument *doc)
902 {
903 const gchar *filename = NULL;
904 gdouble dpi = 0.0;
906 if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
907 g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
908 }
910 GSList *items = NULL;
912 NRRect area;
913 if (sp_export_id || sp_export_area_drawing) {
915 SPObject *o = NULL;
916 SPObject *o_area = NULL;
917 if (sp_export_id && sp_export_area_drawing) {
918 o = doc->getObjectById(sp_export_id);
919 o_area = SP_DOCUMENT_ROOT (doc);
920 } else if (sp_export_id) {
921 o = doc->getObjectById(sp_export_id);
922 o_area = o;
923 } else if (sp_export_area_drawing) {
924 o = SP_DOCUMENT_ROOT (doc);
925 o_area = o;
926 }
928 if (o) {
929 if (!SP_IS_ITEM (o)) {
930 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
931 return;
932 }
934 items = g_slist_prepend (items, SP_ITEM(o));
936 if (sp_export_id_only) {
937 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
938 }
940 if (sp_export_use_hints) {
942 // retrieve export filename hint
943 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
944 if (fn_hint) {
945 if (sp_export_png) {
946 g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
947 filename = sp_export_png;
948 } else {
949 filename = fn_hint;
950 }
951 } else {
952 g_warning ("Export filename hint not found for the object.");
953 filename = sp_export_png;
954 }
956 // retrieve export dpi hints
957 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
958 if (dpi_hint) {
959 if (sp_export_dpi || sp_export_width || sp_export_height) {
960 g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
961 } else {
962 dpi = atof(dpi_hint);
963 }
964 } else {
965 g_warning ("Export DPI hint not found for the object.");
966 }
968 }
970 // write object bbox to area
971 sp_document_ensure_up_to_date (doc);
972 sp_item_invoke_bbox((SPItem *) o_area, &area, sp_item_i2r_affine((SPItem *) o_area), TRUE);
973 } else {
974 g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
975 return;
976 }
977 }
979 if (sp_export_area) {
980 /* Try to parse area (given in SVG pixels) */
981 if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
982 g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
983 return;
984 }
985 if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
986 g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
987 return;
988 }
989 } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
990 /* Export the whole canvas */
991 sp_document_ensure_up_to_date (doc);
992 area.x0 = SP_ROOT(doc->root)->x.computed;
993 area.y0 = SP_ROOT(doc->root)->y.computed;
994 area.x1 = area.x0 + sp_document_width (doc);
995 area.y1 = area.y0 + sp_document_height (doc);
996 }
998 // set filename and dpi from options, if not yet set from the hints
999 if (!filename) {
1000 if (!sp_export_png) {
1001 g_warning ("No export filename given and no filename hint. Nothing exported.");
1002 return;
1003 }
1004 filename = sp_export_png;
1005 }
1007 if (sp_export_dpi && dpi == 0.0) {
1008 dpi = atof(sp_export_dpi);
1009 if ((dpi < 0.1) || (dpi > 10000.0)) {
1010 g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1011 return;
1012 }
1013 g_print("DPI: %g\n", dpi);
1014 }
1016 if (sp_export_area_snap) {
1017 area.x0 = std::floor (area.x0);
1018 area.y0 = std::floor (area.y0);
1019 area.x1 = std::ceil (area.x1);
1020 area.y1 = std::ceil (area.y1);
1021 }
1023 // default dpi
1024 if (dpi == 0.0)
1025 dpi = PX_PER_IN;
1027 unsigned long int width = 0;
1028 unsigned long int height = 0;
1030 if (sp_export_width) {
1031 width = strtoul(sp_export_width, NULL, 0);
1032 if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
1033 g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
1034 return;
1035 }
1036 dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
1037 }
1039 if (sp_export_height) {
1040 height = strtoul(sp_export_height, NULL, 0);
1041 if ((height < 1) || (height > PNG_UINT_31_MAX)) {
1042 g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
1043 return;
1044 }
1045 dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
1046 }
1048 if (!sp_export_width) {
1049 width = (unsigned long int) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1050 }
1052 if (!sp_export_height) {
1053 height = (unsigned long int) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1054 }
1056 guint32 bgcolor = 0x00000000;
1057 if (sp_export_background) {
1058 // override the page color
1059 bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1060 bgcolor |= 0xff; // default is no opacity
1061 } else {
1062 // read from namedview
1063 Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1064 if (nv && nv->attribute("pagecolor"))
1065 bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1066 if (nv && nv->attribute("inkscape:pageopacity"))
1067 bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1068 }
1070 if (sp_export_background_opacity) {
1071 // override opacity
1072 gfloat value;
1073 if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1074 if (value > 1.0) {
1075 value = CLAMP (value, 1.0f, 255.0f);
1076 bgcolor &= (guint32) 0xffffff00;
1077 bgcolor |= (guint32) floor(value);
1078 } else {
1079 value = CLAMP (value, 0.0f, 1.0f);
1080 bgcolor &= (guint32) 0xffffff00;
1081 bgcolor |= SP_COLOR_F_TO_U(value);
1082 }
1083 }
1084 }
1086 g_print("Background RRGGBBAA: %08x\n", bgcolor);
1088 g_print("Area %g:%g:%g:%g exported to %lu x %lu pixels (%g dpi)\n", area.x0, area.y0, area.x1, area.y1, width, height, dpi);
1090 g_print("Bitmap saved as: %s\n", filename);
1092 if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1093 sp_export_png_file(doc, filename, area.x0, area.y0, area.x1, area.y1, width, height, dpi, dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : NULL);
1094 } else {
1095 g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1096 }
1098 g_slist_free (items);
1099 }
1102 /**
1103 * Perform an export of either PS or EPS.
1104 *
1105 * \param doc Document to export.
1106 * \param uri URI to export to.
1107 * \param mime MIME type to export as.
1108 */
1110 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1111 {
1112 Inkscape::Extension::DB::OutputList o;
1113 Inkscape::Extension::db.get_output_list(o);
1114 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1115 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1116 i++;
1117 }
1119 if (i == o.end())
1120 {
1121 g_warning ("Could not find an extension to export to MIME type %s.", mime);
1122 return;
1123 }
1125 bool old_text_to_path = false;
1126 bool old_font_embedded = false;
1127 bool old_bbox_page = false;
1129 try {
1130 old_text_to_path = (*i)->get_param_bool("textToPath");
1131 (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1132 }
1133 catch (...) {
1134 g_warning ("Could not set export-text-to-path option for this export.");
1135 }
1137 try {
1138 old_font_embedded = (*i)->get_param_bool("fontEmbedded");
1139 (*i)->set_param_bool("fontEmbedded", sp_export_font);
1140 }
1141 catch (...) {
1142 g_warning ("Could not set export-font option for this export.");
1143 }
1145 try {
1146 old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1147 (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1148 }
1149 catch (...) {
1150 g_warning ("Could not set export-bbox-page option for this export.");
1151 }
1153 (*i)->save(doc, uri);
1155 try {
1156 (*i)->set_param_bool("textToPath", old_text_to_path);
1157 (*i)->set_param_bool("fontEmbedded", old_font_embedded);
1158 (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1159 }
1160 catch (...) {
1162 }
1163 }
1165 /**
1166 * Perform a PDF export
1167 *
1168 * \param doc Document to export.
1169 * \param uri URI to export to.
1170 * \param mime MIME type to export as.
1171 */
1173 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1174 {
1175 Inkscape::Extension::DB::OutputList o;
1176 Inkscape::Extension::db.get_output_list(o);
1177 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1178 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1179 i++;
1180 }
1182 if (i == o.end())
1183 {
1184 g_warning ("Could not find an extension to export to MIME type %s.", mime);
1185 return;
1186 }
1188 if (sp_export_id) {
1189 SPObject *o = doc->getObjectById(sp_export_id);
1190 if (o == NULL) {
1191 g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1192 return;
1193 }
1194 (*i)->set_param_string ("exportId", sp_export_id);
1195 } else {
1196 (*i)->set_param_string ("exportId", "");
1197 }
1199 if (sp_export_area_drawing) {
1200 (*i)->set_param_bool ("exportDrawing", TRUE);
1201 } else {
1202 (*i)->set_param_bool ("exportDrawing", FALSE);
1203 }
1205 (*i)->save(doc, uri);
1206 }
1208 #ifdef WIN32
1209 /**
1210 * Export a document to EMF
1211 *
1212 * \param doc Document to export.
1213 * \param uri URI to export to.
1214 * \param mime MIME type to export as (should be "image/x-emf")
1215 */
1217 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1218 {
1219 Inkscape::Extension::DB::OutputList o;
1220 Inkscape::Extension::db.get_output_list(o);
1221 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1222 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1223 i++;
1224 }
1226 if (i == o.end())
1227 {
1228 g_warning ("Could not find an extension to export to MIME type %s.", mime);
1229 return;
1230 }
1232 (*i)->save(doc, uri);
1233 }
1234 #endif //WIN32
1236 #ifdef WIN32
1237 bool replaceArgs( int& argc, char**& argv )
1238 {
1239 bool worked = false;
1241 #ifdef REPLACEARGS_DEBUG
1242 MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1243 #endif // REPLACEARGS_DEBUG
1245 wchar_t* line = GetCommandLineW();
1246 if ( line )
1247 {
1248 #ifdef REPLACEARGS_DEBUG
1249 {
1250 gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1251 if ( utf8Line )
1252 {
1253 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1254 {
1255 char tmp[strlen(safe) + 32];
1256 snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1257 MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1258 }
1259 }
1260 }
1261 #endif // REPLACEARGS_DEBUG
1263 int numArgs = 0;
1264 wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1266 #ifdef REPLACEARGS_ANSI
1267 // test code for trying things on Win95/98/ME
1268 if ( !parsed )
1269 {
1270 #ifdef REPLACEARGS_DEBUG
1271 MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1272 #endif // REPLACEARGS_DEBUG
1273 int lineLen = wcslen(line) + 1;
1274 wchar_t* lineDup = new wchar_t[lineLen];
1275 wcsncpy( lineDup, line, lineLen );
1277 int pos = 0;
1278 bool inQuotes = false;
1279 bool inWhitespace = true;
1280 std::vector<int> places;
1281 while ( lineDup[pos] )
1282 {
1283 if ( inQuotes )
1284 {
1285 if ( lineDup[pos] == L'"' )
1286 {
1287 inQuotes = false;
1288 }
1289 }
1290 else if ( lineDup[pos] == L'"' )
1291 {
1292 inQuotes = true;
1293 inWhitespace = false;
1294 places.push_back(pos);
1295 }
1296 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1297 {
1298 if ( !inWhitespace )
1299 {
1300 inWhitespace = true;
1301 lineDup[pos] = 0;
1302 }
1303 }
1304 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1305 {
1306 inWhitespace = false;
1307 places.push_back(pos);
1308 }
1309 else
1310 {
1311 // consume
1312 }
1313 pos++;
1314 }
1315 #ifdef REPLACEARGS_DEBUG
1316 {
1317 char tmp[256];
1318 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1319 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1320 }
1321 #endif // REPLACEARGS_DEBUG
1323 wchar_t** block = new wchar_t*[places.size()];
1324 int i = 0;
1325 for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1326 {
1327 block[i++] = &lineDup[*it];
1328 }
1329 parsed = block;
1330 numArgs = places.size();
1331 }
1332 #endif // REPLACEARGS_ANSI
1334 if ( parsed )
1335 {
1336 std::vector<wchar_t*>expandedArgs;
1337 if ( numArgs > 0 )
1338 {
1339 expandedArgs.push_back( parsed[0] );
1340 }
1342 for ( int i1 = 1; i1 < numArgs; i1++ )
1343 {
1344 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1345 wildcarded &= parsed[i1][0] != L'"';
1346 wildcarded &= parsed[i1][0] != L'-';
1347 if ( wildcarded )
1348 {
1349 #ifdef REPLACEARGS_ANSI
1350 WIN32_FIND_DATAA data = {0};
1351 #else
1352 WIN32_FIND_DATAW data = {0};
1353 #endif // REPLACEARGS_ANSI
1355 int baseLen = wcslen(parsed[i1]) + 2;
1356 wchar_t* base = new wchar_t[baseLen];
1357 wcsncpy( base, parsed[i1], baseLen );
1358 wchar_t* last = wcsrchr( base, L'\\' );
1359 if ( last )
1360 {
1361 last[1] = 0;
1362 }
1363 else
1364 {
1365 base[0] = 0;
1366 }
1367 baseLen = wcslen( base );
1369 #ifdef REPLACEARGS_ANSI
1370 char target[MAX_PATH];
1371 if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1372 {
1373 HANDLE hf = FindFirstFileA( target, &data );
1374 #else
1375 HANDLE hf = FindFirstFileW( parsed[i1], &data );
1376 #endif // REPLACEARGS_ANSI
1377 if ( hf != INVALID_HANDLE_VALUE )
1378 {
1379 BOOL found = TRUE;
1380 do
1381 {
1382 #ifdef REPLACEARGS_ANSI
1383 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1384 if ( howMany > 0 )
1385 {
1386 howMany += baseLen;
1387 wchar_t* tmp = new wchar_t[howMany + 1];
1388 wcsncpy( tmp, base, howMany + 1 );
1389 MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1390 expandedArgs.push_back( tmp );
1391 found = FindNextFileA( hf, &data );
1392 }
1393 #else
1394 int howMany = wcslen(data.cFileName) + baseLen;
1395 wchar_t* tmp = new wchar_t[howMany + 1];
1396 wcsncpy( tmp, base, howMany + 1 );
1397 wcsncat( tmp, data.cFileName, howMany + 1 );
1398 expandedArgs.push_back( tmp );
1399 found = FindNextFileW( hf, &data );
1400 #endif // REPLACEARGS_ANSI
1401 } while ( found );
1403 FindClose( hf );
1404 }
1405 else
1406 {
1407 expandedArgs.push_back( parsed[i1] );
1408 }
1409 #ifdef REPLACEARGS_ANSI
1410 }
1411 #endif // REPLACEARGS_ANSI
1413 delete[] base;
1414 }
1415 else
1416 {
1417 expandedArgs.push_back( parsed[i1] );
1418 }
1419 }
1421 {
1422 wchar_t** block = new wchar_t*[expandedArgs.size()];
1423 int iz = 0;
1424 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1425 {
1426 block[iz++] = *it;
1427 }
1428 parsed = block;
1429 numArgs = expandedArgs.size();
1430 }
1432 std::vector<gchar*> newArgs;
1433 for ( int i = 0; i < numArgs; i++ )
1434 {
1435 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1436 if ( replacement )
1437 {
1438 #ifdef REPLACEARGS_DEBUG
1439 gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1441 if ( safe2 )
1442 {
1443 {
1444 char tmp[1024];
1445 snprintf( tmp, sizeof(tmp), " [%2d] = '%s'", i, safe2 );
1446 MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1447 }
1448 g_free( safe2 );
1449 }
1450 #endif // REPLACEARGS_DEBUG
1452 newArgs.push_back( replacement );
1453 }
1454 else
1455 {
1456 newArgs.push_back( blankParam );
1457 }
1458 }
1460 // Now push our munged params to be the new argv and argc
1461 {
1462 char** block = new char*[newArgs.size()];
1463 int iz = 0;
1464 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1465 {
1466 block[iz++] = *it;
1467 }
1468 argv = block;
1469 argc = newArgs.size();
1470 worked = true;
1471 }
1472 }
1473 #ifdef REPLACEARGS_DEBUG
1474 else
1475 {
1476 MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1477 }
1478 #endif // REPLACEARGS_DEBUG
1479 }
1480 #ifdef REPLACEARGS_DEBUG
1481 else
1482 {
1483 {
1484 MessageBoxA( NULL, "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1485 }
1487 char* line2 = GetCommandLineA();
1488 if ( line2 )
1489 {
1490 gchar *safe = Inkscape::IO::sanitizeString(line2);
1491 {
1492 {
1493 char tmp[strlen(safe) + 32];
1494 snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1495 MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1496 }
1497 }
1498 }
1499 else
1500 {
1501 MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1502 }
1503 }
1504 #endif // REPLACEARGS_DEBUG
1506 return worked;
1507 }
1508 #endif // WIN32
1510 static GSList *
1511 sp_process_args(poptContext ctx)
1512 {
1513 GSList *fl = NULL;
1515 gint a;
1516 while ((a = poptGetNextOpt(ctx)) >= 0) {
1517 switch (a) {
1518 case SP_ARG_FILE: {
1519 gchar const *fn = poptGetOptArg(ctx);
1520 if (fn != NULL) {
1521 fl = g_slist_append(fl, g_strdup(fn));
1522 }
1523 break;
1524 }
1525 case SP_ARG_VERSION: {
1526 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1527 exit(0);
1528 break;
1529 }
1530 case SP_ARG_EXTENSIONDIR: {
1531 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1532 exit(0);
1533 break;
1534 }
1535 case SP_ARG_VERB_LIST: {
1536 // This really shouldn't go here, we should init the app.
1537 // But, since we're just exiting in this path, there is
1538 // no harm, and this is really a better place to put
1539 // everything else.
1540 Inkscape::Extension::init();
1541 Inkscape::Verb::list();
1542 exit(0);
1543 break;
1544 }
1545 case SP_ARG_VERB:
1546 case SP_ARG_SELECT: {
1547 gchar const *arg = poptGetOptArg(ctx);
1548 if (arg != NULL) {
1549 // printf("Adding in: %s\n", arg);
1550 new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1551 }
1552 break;
1553 }
1554 default: {
1555 break;
1556 }
1557 }
1558 }
1560 gchar const ** const args = poptGetArgs(ctx);
1561 if (args != NULL) {
1562 for (unsigned i = 0; args[i] != NULL; i++) {
1563 fl = g_slist_append(fl, g_strdup(args[i]));
1564 }
1565 }
1567 return fl;
1568 }
1571 /*
1572 Local Variables:
1573 mode:c++
1574 c-file-style:"stroustrup"
1575 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1576 indent-tabs-mode:nil
1577 fill-column:99
1578 End:
1579 */
1580 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :