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 #ifdef WIN32
417 static int _win32_set_inkscape_env(char *argv0)
418 {
419 CHAR szFullPath[_MAX_PATH];
421 CHAR szDrive[_MAX_DRIVE];
422 CHAR szDir[_MAX_DIR];
423 CHAR szFile[_MAX_FNAME];
424 CHAR szExt[_MAX_EXT];
426 std::string tmp;
428 if (GetModuleFileName(NULL, szFullPath, sizeof(szFullPath)) == 0) {
429 strcpy(szFullPath, argv0);
430 }
432 _splitpath(szFullPath, szDrive, szDir, szFile, szExt);
433 strcpy(szFullPath, szDrive);
434 strcat(szFullPath, szDir);
436 char *oldenv = getenv("PATH");
437 tmp = "PATH=";
438 tmp += szFullPath;
439 tmp += ";";
440 tmp += szFullPath;
441 tmp += "python;";
442 tmp += szFullPath;
443 tmp += "perl";
444 if(oldenv != NULL) {
445 tmp += ";";
446 tmp += oldenv;
447 }
448 _putenv(tmp.c_str());
450 oldenv = getenv("PYTHONPATH");
451 tmp = "PYTHONPATH=";
452 tmp += szFullPath;
453 tmp += "python;";
454 tmp += szFullPath;
455 tmp += "python\\Lib;";
456 tmp += szFullPath;
457 tmp += "python\\DLLs";
458 if(oldenv != NULL) {
459 tmp += ";";
460 tmp += oldenv;
461 }
462 _putenv(tmp.c_str());
464 return 0;
465 }
466 #endif
468 int
469 main(int argc, char **argv)
470 {
471 #ifdef HAVE_FPSETMASK
472 /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__. It's probably
473 safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
474 the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
475 fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
476 #endif
478 #ifdef ENABLE_NLS
479 #ifdef WIN32
480 _win32_set_inkscape_env(argv[0]);
481 RegistryTool rt;
482 rt.setPathInfo();
483 gchar *pathBuf = g_strconcat(g_path_get_dirname(argv[0]), "\\", PACKAGE_LOCALE_DIR, NULL);
484 bindtextdomain(GETTEXT_PACKAGE, pathBuf);
485 g_free(pathBuf);
486 #else
487 #ifdef ENABLE_BINRELOC
488 bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
489 #else
490 bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
491 #endif
492 #endif
493 // Allow the user to override the locale directory by setting
494 // the environment variable INKSCAPE_LOCALEDIR.
495 char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR");
496 if (inkscape_localedir != NULL) {
497 bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
498 }
499 #endif
501 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
503 #ifdef ENABLE_NLS
504 textdomain(GETTEXT_PACKAGE);
505 #endif
507 LIBXML_TEST_VERSION
509 Inkscape::GC::init();
511 Inkscape::Debug::Logger::init();
513 gboolean use_gui;
514 #ifndef WIN32
515 use_gui = (getenv("DISPLAY") != NULL);
516 #else
517 /*
518 Set the current directory to the directory of the
519 executable. This seems redundant, but is needed for
520 when inkscape.exe is executed from another directory.
521 We use relative paths on win32.
522 HKCR\svgfile\shell\open\command is a good example
523 */
524 /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
525 char *homedir = g_path_get_dirname(argv[0]);
526 SetCurrentDirectory(homedir);
527 g_free(homedir);
529 use_gui = TRUE;
530 #endif
531 /* Test whether with/without GUI is forced */
532 for (int i = 1; i < argc; i++) {
533 if (!strcmp(argv[i], "-z")
534 || !strcmp(argv[i], "--without-gui")
535 || !strcmp(argv[i], "-p")
536 || !strncmp(argv[i], "--print", 7)
537 || !strcmp(argv[i], "-e")
538 || !strncmp(argv[i], "--export-png", 12)
539 || !strcmp(argv[i], "-l")
540 || !strncmp(argv[i], "--export-plain-svg", 12)
541 || !strcmp(argv[i], "-i")
542 || !strncmp(argv[i], "--export-area-drawing", 21)
543 || !strcmp(argv[i], "-D")
544 || !strncmp(argv[i], "--export-area-canvas", 20)
545 || !strcmp(argv[i], "-C")
546 || !strncmp(argv[i], "--export-id", 12)
547 || !strcmp(argv[i], "-P")
548 || !strncmp(argv[i], "--export-ps", 11)
549 || !strcmp(argv[i], "-E")
550 || !strncmp(argv[i], "--export-eps", 12)
551 || !strcmp(argv[i], "-A")
552 || !strncmp(argv[i], "--export-pdf", 12)
553 #ifdef WIN32
554 || !strcmp(argv[i], "-M")
555 || !strncmp(argv[i], "--export-emf", 12)
556 #endif //WIN32
557 || !strcmp(argv[i], "-W")
558 || !strncmp(argv[i], "--query-width", 13)
559 || !strcmp(argv[i], "-H")
560 || !strncmp(argv[i], "--query-height", 14)
561 || !strcmp(argv[i], "-S")
562 || !strncmp(argv[i], "--query-all", 11)
563 || !strcmp(argv[i], "-X")
564 || !strncmp(argv[i], "--query-x", 13)
565 || !strcmp(argv[i], "-Y")
566 || !strncmp(argv[i], "--query-y", 14)
567 || !strcmp(argv[i], "--vacuum-defs")
568 )
569 {
570 /* main_console handles any exports -- not the gui */
571 use_gui = FALSE;
572 break;
573 } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
574 use_gui = TRUE;
575 break;
576 }
577 }
579 #ifdef WIN32
580 #ifndef REPLACEARGS_ANSI
581 if ( PrintWin32::is_os_wide() )
582 #endif // REPLACEARGS_ANSI
583 {
584 // If the call fails, we'll need to convert charsets
585 needToRecodeParams = !replaceArgs( argc, argv );
586 }
587 #endif // WIN32
589 /// \todo Should this be a static object (see inkscape.cpp)?
590 Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
592 return app.run();
593 }
595 void fixupSingleFilename( gchar **orig, gchar **spare )
596 {
597 if ( orig && *orig && **orig ) {
598 GError *error = NULL;
599 gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
600 if ( newFileName )
601 {
602 *orig = newFileName;
603 if ( spare ) {
604 *spare = newFileName;
605 }
606 // g_message("Set a replacement fixup");
607 }
608 }
609 }
611 GSList *fixupFilenameEncoding( GSList* fl )
612 {
613 GSList *newFl = NULL;
614 while ( fl ) {
615 gchar *fn = static_cast<gchar*>(fl->data);
616 fl = g_slist_remove( fl, fl->data );
617 gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
618 if ( newFileName ) {
620 if ( 0 )
621 {
622 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
623 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
624 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
625 "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
626 gtk_dialog_run (GTK_DIALOG (w));
627 gtk_widget_destroy (w);
628 g_free(safeNewFn);
629 g_free(safeFn);
630 }
632 g_free( fn );
633 fn = newFileName;
634 newFileName = 0;
635 }
636 else
637 if ( 0 )
638 {
639 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
640 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
641 gtk_dialog_run (GTK_DIALOG (w));
642 gtk_widget_destroy (w);
643 g_free(safeFn);
644 }
645 newFl = g_slist_append( newFl, fn );
646 }
647 return newFl;
648 }
650 int sp_common_main( int argc, char const **argv, GSList **flDest )
651 {
652 /// \todo fixme: Move these to some centralized location (Lauris)
653 sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
654 sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
657 // temporarily switch gettext encoding to locale, so that help messages can be output properly
658 gchar const *charset;
659 g_get_charset(&charset);
661 bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
663 poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
664 poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
665 g_return_val_if_fail(ctx != NULL, 1);
667 /* Collect own arguments */
668 GSList *fl = sp_process_args(ctx);
669 poptFreeContext(ctx);
671 // now switch gettext back to UTF-8 (for GUI)
672 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
674 // Now let's see if the file list still holds up
675 if ( needToRecodeParams )
676 {
677 fl = fixupFilenameEncoding( fl );
678 }
680 // Check the globals for filename-fixup
681 if ( needToRecodeParams )
682 {
683 fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
684 fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
685 fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
686 }
687 else
688 {
689 if ( sp_export_png )
690 sp_export_png_utf8 = g_strdup( sp_export_png );
691 if ( sp_export_svg )
692 sp_export_svg_utf8 = g_strdup( sp_export_svg );
693 if ( sp_global_printer )
694 sp_global_printer_utf8 = g_strdup( sp_global_printer );
695 }
697 // Return the list if wanted, else free it up.
698 if ( flDest ) {
699 *flDest = fl;
700 fl = 0;
701 } else {
702 while ( fl ) {
703 g_free( fl->data );
704 fl = g_slist_remove( fl, fl->data );
705 }
706 }
707 return 0;
708 }
710 static void
711 snooper(GdkEvent *event, gpointer /*data*/) {
712 if(inkscape_mapalt()) /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
713 {
714 GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
715 switch (event->type) {
716 case GDK_MOTION_NOTIFY:
717 if(event->motion.state & mapping) {
718 event->motion.state|=GDK_MOD1_MASK;
719 }
720 break;
721 case GDK_BUTTON_PRESS:
722 if(event->button.state & mapping) {
723 event->button.state|=GDK_MOD1_MASK;
724 }
725 break;
726 case GDK_KEY_PRESS:
727 if(event->key.state & mapping) {
728 event->key.state|=GDK_MOD1_MASK;
729 }
730 break;
731 default:
732 break;
733 }
734 }
735 gtk_main_do_event (event);
736 }
738 int
739 sp_main_gui(int argc, char const **argv)
740 {
741 Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
743 GSList *fl = NULL;
744 int retVal = sp_common_main( argc, argv, &fl );
745 g_return_val_if_fail(retVal == 0, 1);
747 inkscape_gtk_stock_init();
749 gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
751 Inkscape::Debug::log_display_config();
753 /* Set default icon */
754 gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
755 if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
756 gtk_window_set_default_icon_from_file(filename, NULL);
757 }
758 g_free (filename);
759 filename = 0;
761 gboolean create_new = TRUE;
763 /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
764 inkscape_application_init(argv[0], true);
766 while (fl) {
767 if (sp_file_open((gchar *)fl->data,NULL)) {
768 create_new=FALSE;
769 }
770 fl = g_slist_remove(fl, fl->data);
771 }
772 if (create_new) {
773 sp_file_new_default();
774 }
776 Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
777 main_instance.run();
779 #ifdef WIN32
780 //We might not need anything here
781 //sp_win32_finish(); <-- this is a NOP func
782 #endif
784 return 0;
785 }
787 int
788 sp_main_console(int argc, char const **argv)
789 {
790 /* We are started in text mode */
792 /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
793 * in a non-Gtk environment. Used in libnrtype's
794 * FontInstance.cpp and FontFactory.cpp.
795 * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
796 */
797 g_type_init();
798 char **argv2 = const_cast<char **>(argv);
799 gtk_init_check( &argc, &argv2 );
800 //setlocale(LC_ALL, "");
802 GSList *fl = NULL;
803 int retVal = sp_common_main( argc, argv, &fl );
804 g_return_val_if_fail(retVal == 0, 1);
806 if (fl == NULL) {
807 g_print("Nothing to do!\n");
808 exit(0);
809 }
811 inkscape_application_init(argv[0], false);
813 while (fl) {
814 SPDocument *doc;
816 doc = Inkscape::Extension::open(NULL, (gchar *)fl->data);
817 if (doc == NULL) {
818 doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), (gchar *)fl->data);
819 }
820 if (doc == NULL) {
821 g_warning("Specified document %s cannot be opened (is it valid SVG file?)", (gchar *) fl->data);
822 } else {
823 if (sp_vacuum_defs) {
824 vacuum_document(doc);
825 }
826 if (sp_vacuum_defs && !sp_export_svg) {
827 // save under the name given in the command line
828 sp_repr_save_file(doc->rdoc, (gchar *)fl->data, SP_SVG_NS_URI);
829 }
830 if (sp_global_printer) {
831 sp_print_document_to_file(doc, sp_global_printer);
832 }
833 if (sp_export_png) {
834 sp_do_export_png(doc);
835 }
836 if (sp_export_svg) {
837 Inkscape::XML::Document *rdoc;
838 Inkscape::XML::Node *repr;
839 rdoc = sp_repr_document_new("svg:svg");
840 repr = rdoc->root();
841 repr = sp_document_root(doc)->updateRepr(repr, SP_OBJECT_WRITE_BUILD);
842 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
843 }
844 if (sp_export_ps) {
845 do_export_ps(doc, sp_export_ps, "image/x-postscript");
846 }
847 if (sp_export_eps) {
848 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
849 }
850 if (sp_export_pdf) {
851 do_export_pdf(doc, sp_export_pdf, "application/pdf");
852 }
853 #ifdef WIN32
854 if (sp_export_emf) {
855 do_export_emf(doc, sp_export_emf, "image/x-emf");
856 }
857 #endif //WIN32
858 if (sp_query_all) {
859 do_query_all (doc);
860 } else if (sp_query_width || sp_query_height) {
861 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
862 } else if (sp_query_x || sp_query_y) {
863 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
864 }
865 }
867 fl = g_slist_remove(fl, fl->data);
868 }
870 inkscape_unref();
872 return 0;
873 }
875 static void
876 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
877 {
878 SPObject *o = NULL;
880 if (id) {
881 o = doc->getObjectById(id);
882 if (o) {
883 if (!SP_IS_ITEM (o)) {
884 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
885 return;
886 }
887 } else {
888 g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
889 return;
890 }
891 } else {
892 o = SP_DOCUMENT_ROOT(doc);
893 }
895 if (o) {
896 sp_document_ensure_up_to_date (doc);
897 SPItem *item = ((SPItem *) o);
899 // "true" SVG bbox for scripting
900 NR::Maybe<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
901 if (area) {
902 Inkscape::SVGOStringStream os;
903 if (extent) {
904 os << area->extent(axis);
905 } else {
906 os << area->min()[axis];
907 }
908 g_print ("%s", os.str().c_str());
909 } else {
910 g_print("0");
911 }
912 }
913 }
915 static void
916 do_query_all (SPDocument *doc)
917 {
918 SPObject *o = NULL;
920 o = SP_DOCUMENT_ROOT(doc);
922 if (o) {
923 sp_document_ensure_up_to_date (doc);
924 do_query_all_recurse(o);
925 }
926 }
928 static void
929 do_query_all_recurse (SPObject *o)
930 {
931 SPItem *item = ((SPItem *) o);
932 if (o->id && SP_IS_ITEM(item)) {
933 NR::Maybe<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
934 if (area) {
935 Inkscape::SVGOStringStream os;
936 os << o->id;
937 os << "," << area->min()[NR::X];
938 os << "," << area->min()[NR::Y];
939 os << "," << area->extent(NR::X);
940 os << "," << area->extent(NR::Y);
941 g_print ("%s\n", os.str().c_str());
942 }
943 }
945 SPObject *child = o->children;
946 while (child) {
947 do_query_all_recurse (child);
948 child = child->next;
949 }
950 }
953 static void
954 sp_do_export_png(SPDocument *doc)
955 {
956 const gchar *filename = NULL;
957 gdouble dpi = 0.0;
959 if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
960 g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
961 }
963 GSList *items = NULL;
965 NRRect area;
966 if (sp_export_id || sp_export_area_drawing) {
968 SPObject *o = NULL;
969 SPObject *o_area = NULL;
970 if (sp_export_id && sp_export_area_drawing) {
971 o = doc->getObjectById(sp_export_id);
972 o_area = SP_DOCUMENT_ROOT (doc);
973 } else if (sp_export_id) {
974 o = doc->getObjectById(sp_export_id);
975 o_area = o;
976 } else if (sp_export_area_drawing) {
977 o = SP_DOCUMENT_ROOT (doc);
978 o_area = o;
979 }
981 if (o) {
982 if (!SP_IS_ITEM (o)) {
983 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
984 return;
985 }
987 items = g_slist_prepend (items, SP_ITEM(o));
989 if (sp_export_id_only) {
990 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
991 }
993 if (sp_export_use_hints) {
995 // retrieve export filename hint
996 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
997 if (fn_hint) {
998 if (sp_export_png) {
999 g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
1000 filename = sp_export_png;
1001 } else {
1002 filename = fn_hint;
1003 }
1004 } else {
1005 g_warning ("Export filename hint not found for the object.");
1006 filename = sp_export_png;
1007 }
1009 // retrieve export dpi hints
1010 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
1011 if (dpi_hint) {
1012 if (sp_export_dpi || sp_export_width || sp_export_height) {
1013 g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
1014 } else {
1015 dpi = atof(dpi_hint);
1016 }
1017 } else {
1018 g_warning ("Export DPI hint not found for the object.");
1019 }
1021 }
1023 // write object bbox to area
1024 sp_document_ensure_up_to_date (doc);
1025 sp_item_invoke_bbox((SPItem *) o_area, &area, sp_item_i2r_affine((SPItem *) o_area), TRUE);
1026 } else {
1027 g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1028 return;
1029 }
1030 }
1032 if (sp_export_area) {
1033 /* Try to parse area (given in SVG pixels) */
1034 if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
1035 g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
1036 return;
1037 }
1038 if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
1039 g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
1040 return;
1041 }
1042 } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
1043 /* Export the whole canvas */
1044 sp_document_ensure_up_to_date (doc);
1045 area.x0 = SP_ROOT(doc->root)->x.computed;
1046 area.y0 = SP_ROOT(doc->root)->y.computed;
1047 area.x1 = area.x0 + sp_document_width (doc);
1048 area.y1 = area.y0 + sp_document_height (doc);
1049 }
1051 // set filename and dpi from options, if not yet set from the hints
1052 if (!filename) {
1053 if (!sp_export_png) {
1054 g_warning ("No export filename given and no filename hint. Nothing exported.");
1055 return;
1056 }
1057 filename = sp_export_png;
1058 }
1060 if (sp_export_dpi && dpi == 0.0) {
1061 dpi = atof(sp_export_dpi);
1062 if ((dpi < 0.1) || (dpi > 10000.0)) {
1063 g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1064 return;
1065 }
1066 g_print("DPI: %g\n", dpi);
1067 }
1069 if (sp_export_area_snap) {
1070 area.x0 = std::floor (area.x0);
1071 area.y0 = std::floor (area.y0);
1072 area.x1 = std::ceil (area.x1);
1073 area.y1 = std::ceil (area.y1);
1074 }
1076 // default dpi
1077 if (dpi == 0.0)
1078 dpi = PX_PER_IN;
1080 unsigned long int width = 0;
1081 unsigned long int height = 0;
1083 if (sp_export_width) {
1084 width = strtoul(sp_export_width, NULL, 0);
1085 if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
1086 g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
1087 return;
1088 }
1089 dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
1090 }
1092 if (sp_export_height) {
1093 height = strtoul(sp_export_height, NULL, 0);
1094 if ((height < 1) || (height > PNG_UINT_31_MAX)) {
1095 g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
1096 return;
1097 }
1098 dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
1099 }
1101 if (!sp_export_width) {
1102 width = (unsigned long int) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1103 }
1105 if (!sp_export_height) {
1106 height = (unsigned long int) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1107 }
1109 guint32 bgcolor = 0x00000000;
1110 if (sp_export_background) {
1111 // override the page color
1112 bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1113 bgcolor |= 0xff; // default is no opacity
1114 } else {
1115 // read from namedview
1116 Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1117 if (nv && nv->attribute("pagecolor"))
1118 bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1119 if (nv && nv->attribute("inkscape:pageopacity"))
1120 bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1121 }
1123 if (sp_export_background_opacity) {
1124 // override opacity
1125 gfloat value;
1126 if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1127 if (value > 1.0) {
1128 value = CLAMP (value, 1.0f, 255.0f);
1129 bgcolor &= (guint32) 0xffffff00;
1130 bgcolor |= (guint32) floor(value);
1131 } else {
1132 value = CLAMP (value, 0.0f, 1.0f);
1133 bgcolor &= (guint32) 0xffffff00;
1134 bgcolor |= SP_COLOR_F_TO_U(value);
1135 }
1136 }
1137 }
1139 g_print("Background RRGGBBAA: %08x\n", bgcolor);
1141 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);
1143 g_print("Bitmap saved as: %s\n", filename);
1145 if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1146 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);
1147 } else {
1148 g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1149 }
1151 g_slist_free (items);
1152 }
1155 /**
1156 * Perform an export of either PS or EPS.
1157 *
1158 * \param doc Document to export.
1159 * \param uri URI to export to.
1160 * \param mime MIME type to export as.
1161 */
1163 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1164 {
1165 Inkscape::Extension::DB::OutputList o;
1166 Inkscape::Extension::db.get_output_list(o);
1167 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1168 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1169 i++;
1170 }
1172 if (i == o.end())
1173 {
1174 g_warning ("Could not find an extension to export to MIME type %s.", mime);
1175 return;
1176 }
1178 bool old_text_to_path = false;
1179 bool old_font_embedded = false;
1180 bool old_bbox_page = false;
1182 try {
1183 old_text_to_path = (*i)->get_param_bool("textToPath");
1184 (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1185 }
1186 catch (...) {
1187 g_warning ("Could not set export-text-to-path option for this export.");
1188 }
1190 try {
1191 old_font_embedded = (*i)->get_param_bool("fontEmbedded");
1192 (*i)->set_param_bool("fontEmbedded", sp_export_font);
1193 }
1194 catch (...) {
1195 g_warning ("Could not set export-font option for this export.");
1196 }
1198 try {
1199 old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1200 (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1201 }
1202 catch (...) {
1203 g_warning ("Could not set export-bbox-page option for this export.");
1204 }
1206 (*i)->save(doc, uri);
1208 try {
1209 (*i)->set_param_bool("textToPath", old_text_to_path);
1210 (*i)->set_param_bool("fontEmbedded", old_font_embedded);
1211 (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1212 }
1213 catch (...) {
1215 }
1216 }
1218 /**
1219 * Perform a PDF export
1220 *
1221 * \param doc Document to export.
1222 * \param uri URI to export to.
1223 * \param mime MIME type to export as.
1224 */
1226 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1227 {
1228 Inkscape::Extension::DB::OutputList o;
1229 Inkscape::Extension::db.get_output_list(o);
1230 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1231 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1232 i++;
1233 }
1235 if (i == o.end())
1236 {
1237 g_warning ("Could not find an extension to export to MIME type %s.", mime);
1238 return;
1239 }
1241 if (sp_export_id) {
1242 SPObject *o = doc->getObjectById(sp_export_id);
1243 if (o == NULL) {
1244 g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1245 return;
1246 }
1247 (*i)->set_param_string ("exportId", sp_export_id);
1248 } else {
1249 (*i)->set_param_string ("exportId", "");
1250 }
1252 if (sp_export_area_drawing) {
1253 (*i)->set_param_bool ("exportDrawing", TRUE);
1254 } else {
1255 (*i)->set_param_bool ("exportDrawing", FALSE);
1256 }
1258 (*i)->save(doc, uri);
1259 }
1261 #ifdef WIN32
1262 /**
1263 * Export a document to EMF
1264 *
1265 * \param doc Document to export.
1266 * \param uri URI to export to.
1267 * \param mime MIME type to export as (should be "image/x-emf")
1268 */
1270 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1271 {
1272 Inkscape::Extension::DB::OutputList o;
1273 Inkscape::Extension::db.get_output_list(o);
1274 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1275 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1276 i++;
1277 }
1279 if (i == o.end())
1280 {
1281 g_warning ("Could not find an extension to export to MIME type %s.", mime);
1282 return;
1283 }
1285 (*i)->save(doc, uri);
1286 }
1287 #endif //WIN32
1289 #ifdef WIN32
1290 bool replaceArgs( int& argc, char**& argv )
1291 {
1292 bool worked = false;
1294 #ifdef REPLACEARGS_DEBUG
1295 MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1296 #endif // REPLACEARGS_DEBUG
1298 wchar_t* line = GetCommandLineW();
1299 if ( line )
1300 {
1301 #ifdef REPLACEARGS_DEBUG
1302 {
1303 gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1304 if ( utf8Line )
1305 {
1306 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1307 {
1308 char tmp[strlen(safe) + 32];
1309 snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1310 MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1311 }
1312 }
1313 }
1314 #endif // REPLACEARGS_DEBUG
1316 int numArgs = 0;
1317 wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1319 #ifdef REPLACEARGS_ANSI
1320 // test code for trying things on Win95/98/ME
1321 if ( !parsed )
1322 {
1323 #ifdef REPLACEARGS_DEBUG
1324 MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1325 #endif // REPLACEARGS_DEBUG
1326 int lineLen = wcslen(line) + 1;
1327 wchar_t* lineDup = new wchar_t[lineLen];
1328 wcsncpy( lineDup, line, lineLen );
1330 int pos = 0;
1331 bool inQuotes = false;
1332 bool inWhitespace = true;
1333 std::vector<int> places;
1334 while ( lineDup[pos] )
1335 {
1336 if ( inQuotes )
1337 {
1338 if ( lineDup[pos] == L'"' )
1339 {
1340 inQuotes = false;
1341 }
1342 }
1343 else if ( lineDup[pos] == L'"' )
1344 {
1345 inQuotes = true;
1346 inWhitespace = false;
1347 places.push_back(pos);
1348 }
1349 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1350 {
1351 if ( !inWhitespace )
1352 {
1353 inWhitespace = true;
1354 lineDup[pos] = 0;
1355 }
1356 }
1357 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1358 {
1359 inWhitespace = false;
1360 places.push_back(pos);
1361 }
1362 else
1363 {
1364 // consume
1365 }
1366 pos++;
1367 }
1368 #ifdef REPLACEARGS_DEBUG
1369 {
1370 char tmp[256];
1371 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1372 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1373 }
1374 #endif // REPLACEARGS_DEBUG
1376 wchar_t** block = new wchar_t*[places.size()];
1377 int i = 0;
1378 for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1379 {
1380 block[i++] = &lineDup[*it];
1381 }
1382 parsed = block;
1383 numArgs = places.size();
1384 }
1385 #endif // REPLACEARGS_ANSI
1387 if ( parsed )
1388 {
1389 std::vector<wchar_t*>expandedArgs;
1390 if ( numArgs > 0 )
1391 {
1392 expandedArgs.push_back( parsed[0] );
1393 }
1395 for ( int i1 = 1; i1 < numArgs; i1++ )
1396 {
1397 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1398 wildcarded &= parsed[i1][0] != L'"';
1399 wildcarded &= parsed[i1][0] != L'-';
1400 if ( wildcarded )
1401 {
1402 #ifdef REPLACEARGS_ANSI
1403 WIN32_FIND_DATAA data = {0};
1404 #else
1405 WIN32_FIND_DATAW data = {0};
1406 #endif // REPLACEARGS_ANSI
1408 int baseLen = wcslen(parsed[i1]) + 2;
1409 wchar_t* base = new wchar_t[baseLen];
1410 wcsncpy( base, parsed[i1], baseLen );
1411 wchar_t* last = wcsrchr( base, L'\\' );
1412 if ( last )
1413 {
1414 last[1] = 0;
1415 }
1416 else
1417 {
1418 base[0] = 0;
1419 }
1420 baseLen = wcslen( base );
1422 #ifdef REPLACEARGS_ANSI
1423 char target[MAX_PATH];
1424 if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1425 {
1426 HANDLE hf = FindFirstFileA( target, &data );
1427 #else
1428 HANDLE hf = FindFirstFileW( parsed[i1], &data );
1429 #endif // REPLACEARGS_ANSI
1430 if ( hf != INVALID_HANDLE_VALUE )
1431 {
1432 BOOL found = TRUE;
1433 do
1434 {
1435 #ifdef REPLACEARGS_ANSI
1436 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1437 if ( howMany > 0 )
1438 {
1439 howMany += baseLen;
1440 wchar_t* tmp = new wchar_t[howMany + 1];
1441 wcsncpy( tmp, base, howMany + 1 );
1442 MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1443 expandedArgs.push_back( tmp );
1444 found = FindNextFileA( hf, &data );
1445 }
1446 #else
1447 int howMany = wcslen(data.cFileName) + baseLen;
1448 wchar_t* tmp = new wchar_t[howMany + 1];
1449 wcsncpy( tmp, base, howMany + 1 );
1450 wcsncat( tmp, data.cFileName, howMany + 1 );
1451 expandedArgs.push_back( tmp );
1452 found = FindNextFileW( hf, &data );
1453 #endif // REPLACEARGS_ANSI
1454 } while ( found );
1456 FindClose( hf );
1457 }
1458 else
1459 {
1460 expandedArgs.push_back( parsed[i1] );
1461 }
1462 #ifdef REPLACEARGS_ANSI
1463 }
1464 #endif // REPLACEARGS_ANSI
1466 delete[] base;
1467 }
1468 else
1469 {
1470 expandedArgs.push_back( parsed[i1] );
1471 }
1472 }
1474 {
1475 wchar_t** block = new wchar_t*[expandedArgs.size()];
1476 int iz = 0;
1477 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1478 {
1479 block[iz++] = *it;
1480 }
1481 parsed = block;
1482 numArgs = expandedArgs.size();
1483 }
1485 std::vector<gchar*> newArgs;
1486 for ( int i = 0; i < numArgs; i++ )
1487 {
1488 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1489 if ( replacement )
1490 {
1491 #ifdef REPLACEARGS_DEBUG
1492 gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1494 if ( safe2 )
1495 {
1496 {
1497 char tmp[1024];
1498 snprintf( tmp, sizeof(tmp), " [%2d] = '%s'", i, safe2 );
1499 MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1500 }
1501 g_free( safe2 );
1502 }
1503 #endif // REPLACEARGS_DEBUG
1505 newArgs.push_back( replacement );
1506 }
1507 else
1508 {
1509 newArgs.push_back( blankParam );
1510 }
1511 }
1513 // Now push our munged params to be the new argv and argc
1514 {
1515 char** block = new char*[newArgs.size()];
1516 int iz = 0;
1517 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1518 {
1519 block[iz++] = *it;
1520 }
1521 argv = block;
1522 argc = newArgs.size();
1523 worked = true;
1524 }
1525 }
1526 #ifdef REPLACEARGS_DEBUG
1527 else
1528 {
1529 MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1530 }
1531 #endif // REPLACEARGS_DEBUG
1532 }
1533 #ifdef REPLACEARGS_DEBUG
1534 else
1535 {
1536 {
1537 MessageBoxA( NULL, "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1538 }
1540 char* line2 = GetCommandLineA();
1541 if ( line2 )
1542 {
1543 gchar *safe = Inkscape::IO::sanitizeString(line2);
1544 {
1545 {
1546 char tmp[strlen(safe) + 32];
1547 snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1548 MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1549 }
1550 }
1551 }
1552 else
1553 {
1554 MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1555 }
1556 }
1557 #endif // REPLACEARGS_DEBUG
1559 return worked;
1560 }
1561 #endif // WIN32
1563 static GSList *
1564 sp_process_args(poptContext ctx)
1565 {
1566 GSList *fl = NULL;
1568 gint a;
1569 while ((a = poptGetNextOpt(ctx)) >= 0) {
1570 switch (a) {
1571 case SP_ARG_FILE: {
1572 gchar const *fn = poptGetOptArg(ctx);
1573 if (fn != NULL) {
1574 fl = g_slist_append(fl, g_strdup(fn));
1575 }
1576 break;
1577 }
1578 case SP_ARG_VERSION: {
1579 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1580 exit(0);
1581 break;
1582 }
1583 case SP_ARG_EXTENSIONDIR: {
1584 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1585 exit(0);
1586 break;
1587 }
1588 case SP_ARG_VERB_LIST: {
1589 // This really shouldn't go here, we should init the app.
1590 // But, since we're just exiting in this path, there is
1591 // no harm, and this is really a better place to put
1592 // everything else.
1593 Inkscape::Extension::init();
1594 Inkscape::Verb::list();
1595 exit(0);
1596 break;
1597 }
1598 case SP_ARG_VERB:
1599 case SP_ARG_SELECT: {
1600 gchar const *arg = poptGetOptArg(ctx);
1601 if (arg != NULL) {
1602 // printf("Adding in: %s\n", arg);
1603 new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1604 }
1605 break;
1606 }
1607 default: {
1608 break;
1609 }
1610 }
1611 }
1613 gchar const ** const args = poptGetArgs(ctx);
1614 if (args != NULL) {
1615 for (unsigned i = 0; args[i] != NULL; i++) {
1616 fl = g_slist_append(fl, g_strdup(args[i]));
1617 }
1618 }
1620 return fl;
1621 }
1624 /*
1625 Local Variables:
1626 mode:c++
1627 c-file-style:"stroustrup"
1628 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1629 indent-tabs-mode:nil
1630 fill-column:99
1631 End:
1632 */
1633 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :