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