Graphviz 12.0.1~dev.20240716.0800
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "builddate.h"
12#include "config.h"
13// windows.h for win machines
14#if defined(_WIN32) && !defined(__CYGWIN__)
15#include <windows.h>
16#include <windowsx.h>
17#endif
18#include "frmobjectui.h"
19#include "gltemplate.h"
20#include "gui.h"
21#include "gvprpipe.h"
22#include "menucallbacks.h"
23#include "support.h"
24#include "viewport.h"
25#include <cgraph/alloc.h>
26#include <cgraph/exit.h>
27#include <glade/glade.h>
28#include <gtk/gtk.h>
29#include <gtk/gtkgl.h>
30#ifdef ENABLE_NLS
31#include "libintl.h"
32#endif
33#include "glexpose.h"
34#include "glutrender.h"
35#include <assert.h>
36
37#include <getopt.h>
38#include <stdbool.h>
39#include <stdint.h>
40#include <stdlib.h>
41#include <string.h>
42
43#ifdef __APPLE__
44#include <mach-o/dyld.h>
45#endif
46
47#ifdef __FreeBSD__
48#include <sys/sysctl.h>
49#include <sys/types.h>
50#endif
51
52#if !defined(_WIN32)
53#include <unistd.h>
54#endif
55
56static char *smyrnaDir; /* path to directory containin smyrna data files */
57static char *smyrnaGlade;
58
59/* smyrnaPath:
60 * Construct pathname for smyrna data file.
61 * Base file name is given as suffix.
62 * The function resolves the directory containing the data files,
63 * and constructs a complete pathname.
64 * The returned string is malloced, so the application should free
65 * it later.
66 * Returns NULL on error.
67 */
68char *smyrnaPath(char *suffix) {
69 static size_t baselen;
70#ifdef _WIN32
71 char *pathSep = "\\";
72#else
73 char *pathSep = "/";
74#endif
75 assert(smyrnaDir);
76
77 if (baselen == 0) {
78 baselen = strlen(smyrnaDir) + 2;
79 }
80 size_t len = baselen + strlen(suffix);
81 char *buf = gv_calloc(len, sizeof(char));
82 snprintf(buf, len, "%s%s%s", smyrnaDir, pathSep, suffix);
83 return buf;
84}
85
86static char *useString = "Usage: smyrna [-v?] <file>\n\
87 -f<WxH:bits@rate> - full-screen mode\n\
88 -e - draw edges as splines if available\n\
89 -v - verbose\n\
90 -? - print usage\n";
91
92static void usage(int v) {
93 fputs(useString, stdout);
95}
96
97static char *Info[] = {
98 "smyrna", /* Program */
99 PACKAGE_VERSION, /* Version */
100 BUILDDATE /* Build Date */
101};
102
103static char *parseArgs(int argc, char *argv[], ViewInfo *viewinfo) {
104 int c;
105
106 while ((c = getopt(argc, argv, ":eKf:txvV?")) != -1) {
107 switch (c) {
108 case 'e':
109 viewinfo->drawSplines = 1;
110 break;
111 case 'v': // FIXME: deprecate and remove -v in future
112 break;
113 case 'f':
114 viewinfo->guiMode = GUI_FULLSCREEN;
115 viewinfo->optArg = optarg;
116 break;
117
118 case 'V':
119 fprintf(stderr, "%s version %s (%s)\n", Info[0], Info[1], Info[2]);
120 graphviz_exit(0);
121 break;
122 case '?':
123 if (optopt == '\0' || optopt == '?')
124 usage(0);
125 else {
126 fprintf(stderr, "smyrna: option -%c unrecognized\n", optopt);
127 usage(1);
128 }
129 break;
130 }
131 }
132
133 if (optind < argc)
134 return argv[optind];
135 else
136 return NULL;
137}
138
139static void windowedMode(int argc, char *argv[]) {
140 GdkGLConfig *glconfig;
141 /*combo box to show loaded graphs */
142 GtkComboBox *graphComboBox;
143
144 gtk_set_locale();
145 gtk_init(&argc, &argv);
146 if (!(smyrnaGlade))
147 smyrnaGlade = smyrnaPath("smyrna.glade");
148 xml = glade_xml_new(smyrnaGlade, NULL, NULL);
149
150 gladewidget = glade_xml_get_widget(xml, "frmMain");
151 gtk_widget_show(gladewidget);
152 g_signal_connect(gladewidget, "destroy", G_CALLBACK(mQuitSlot), NULL);
153 glade_xml_signal_autoconnect(xml);
154 gtk_gl_init(0, 0);
155 /* Configure OpenGL framebuffer. */
156 glconfig = configure_gl();
157 gladewidget = glade_xml_get_widget(xml, "hbox11");
158
159 gtk_widget_hide(glade_xml_get_widget(xml, "vbox13"));
160 gtk_window_set_deletable(
161 (GtkWindow *)glade_xml_get_widget(xml, "dlgSettings"), 0);
162 gtk_window_set_deletable((GtkWindow *)glade_xml_get_widget(xml, "frmTVNodes"),
163 0);
164 create_window(glconfig, gladewidget);
165 change_cursor(GDK_TOP_LEFT_ARROW);
166
167#ifndef _WIN32
168 glutInit(&argc, argv);
169#endif
170
171 gladewidget = glade_xml_get_widget(xml, "hbox13");
172 graphComboBox = (GtkComboBox *)gtk_combo_box_new_text();
173 gtk_box_pack_end((GtkBox *)gladewidget, (GtkWidget *)graphComboBox, 1, 1, 10);
174 gtk_widget_show((GtkWidget *)graphComboBox);
175 view->graphComboBox = graphComboBox;
176
178 gtk_main();
179}
180
181#if !defined(__APPLE__) && !defined(_WIN32)
183static char *readln(const char *path) {
184
185 char *resolved = NULL;
186 size_t size = 0;
187
188 while (true) {
189
190 // expand target buffer
191 resolved = gv_realloc(resolved, size, size == 0 ? 1024 : (size * 2));
192 size = size == 0 ? 1024 : (size * 2);
193
194 // attempt to resolve
195 {
196 ssize_t written = readlink(path, resolved, size);
197 if (written < 0) {
198 break;
199 }
200 if ((size_t)written < size) {
201 // success
202 resolved[written] = '\0';
203 return resolved;
204 }
205 }
206 }
207
208 // failed
209 free(resolved);
210 return NULL;
211}
212#endif
213
215static char *find_me(void) {
216
217 // macOS
218#ifdef __APPLE__
219 {
220 // determine how many bytes we will need to allocate
221 uint32_t buf_size = 0;
222 int rc = _NSGetExecutablePath(NULL, &buf_size);
223 assert(rc != 0);
224 assert(buf_size > 0);
225
226 char *path = gv_alloc(buf_size);
227
228 // retrieve the actual path
229 if (_NSGetExecutablePath(path, &buf_size) < 0) {
230 fprintf(stderr, "failed to get path for executable.\n");
231 graphviz_exit(EXIT_FAILURE);
232 }
233
234 // try to resolve any levels of symlinks if possible
235 while (true) {
236 char *buf = readln(path);
237 if (buf == NULL)
238 return path;
239
240 free(path);
241 path = buf;
242 }
243 }
244#elif defined(_WIN32)
245 {
246 char *path = NULL;
247 size_t path_size = 0;
248 int rc = 0;
249
250 do {
251 size_t size = path_size == 0 ? 1024 : (path_size * 2);
252 path = gv_realloc(path, path_size, size);
253 path_size = size;
254
255 rc = GetModuleFileName(NULL, path, path_size);
256 if (rc == 0) {
257 fprintf(stderr, "failed to get path for executable.\n");
258 graphviz_exit(EXIT_FAILURE);
259 }
260
261 } while (rc == path_size);
262
263 return path;
264 }
265#else
266
267 // Linux
268 char *path = readln("/proc/self/exe");
269 if (path != NULL)
270 return path;
271
272 // DragonFly BSD, FreeBSD
273 path = readln("/proc/curproc/file");
274 if (path != NULL)
275 return path;
276
277 // NetBSD
278 path = readln("/proc/curproc/exe");
279 if (path != NULL)
280 return path;
281
282// /proc-less FreeBSD
283#ifdef __FreeBSD__
284 {
285 int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
286 static const size_t MIB_LENGTH = sizeof(mib) / sizeof(mib[0]);
287
288 do {
289 // determine how long the path is
290 size_t buf_size = 0;
291 if (sysctl(mib, MIB_LENGTH, NULL, &buf_size, NULL, 0) < 0) {
292 break;
293 }
294 assert(buf_size > 0);
295
296 // make enough space for the target path
297 char *buf = gv_alloc(buf_size);
298
299 // resolve it
300 if (sysctl(mib, MIB_LENGTH, buf, &buf_size, NULL, 0) == 0) {
301 return buf;
302 }
303 free(buf);
304 } while (0);
305 }
306#endif
307#endif
308
309 fprintf(stderr, "failed to get path for executable.\n");
310 graphviz_exit(EXIT_FAILURE);
311}
312
314static char *find_share(void) {
315
316#ifdef _WIN32
317 const char PATH_SEPARATOR = '\\';
318#else
319 const char PATH_SEPARATOR = '/';
320#endif
321
322 // find the path to the `smyrna` binary
323 char *smyrna_exe = find_me();
324
325 // assume it is of the form …/bin/smyrna[.exe] and construct
326 // …/share/graphviz/smyrna
327
328 char *slash = strrchr(smyrna_exe, PATH_SEPARATOR);
329 if (slash == NULL) {
330 fprintf(stderr, "no path separator in path to self, %s\n", smyrna_exe);
331 free(smyrna_exe);
332 graphviz_exit(EXIT_FAILURE);
333 }
334
335 *slash = '\0';
336 slash = strrchr(smyrna_exe, PATH_SEPARATOR);
337 if (slash == NULL) {
338 fprintf(stderr, "no path separator in directory containing self, %s\n",
339 smyrna_exe);
340 free(smyrna_exe);
341 graphviz_exit(EXIT_FAILURE);
342 }
343
344 *slash = '\0';
345 size_t share_len = strlen(smyrna_exe) + strlen("/share/graphviz/smyrna") + 1;
346 char *share = gv_alloc(share_len);
347 snprintf(share, share_len, "%s%cshare%cgraphviz%csmyrna", smyrna_exe,
348 PATH_SEPARATOR, PATH_SEPARATOR, PATH_SEPARATOR);
349 free(smyrna_exe);
350
351 return share;
352}
353
354int main(int argc, char *argv[]) {
355 smyrnaDir = getenv("SMYRNA_PATH");
356 if (!smyrnaDir) {
358 }
359
360 gchar *package_locale_dir;
361#ifdef G_OS_WIN32
362 gchar *package_prefix =
363 g_win32_get_package_installation_directory(NULL, NULL);
364 gchar *package_data_dir = g_build_filename(package_prefix, "share", NULL);
365 package_locale_dir =
366 g_build_filename(package_prefix, "share", "locale", NULL);
367#else
368 package_locale_dir = g_build_filename(smyrnaDir, "locale", NULL);
369#endif /* # */
370#ifdef ENABLE_NLS
371 bindtextdomain(GETTEXT_PACKAGE, package_locale_dir);
372 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
373 textdomain(GETTEXT_PACKAGE);
374#endif
375 view = gv_alloc(sizeof(ViewInfo));
377 view->initFileName = parseArgs(argc, argv, view);
378 if (view->initFileName)
379 view->initFile = 1;
380
382 cb_glutinit(800, 600, &argc, argv, view->optArg);
383 else
384 windowedMode(argc, argv);
385#ifdef G_OS_WIN32
386 g_free(package_prefix);
387 g_free(package_data_dir);
388#endif
389 g_free(package_locale_dir);
390 graphviz_exit(0);
391}
392
Memory allocation wrappers that exit on failure.
static void * gv_realloc(void *ptr, size_t old_size, size_t new_size)
Definition alloc.h:49
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static void * gv_alloc(size_t size)
Definition alloc.h:47
char * suffix
Definition bcomps.c:66
static NORETURN void graphviz_exit(int status)
Definition exit.h:23
GdkGLConfig * configure_gl(void)
Definition gltemplate.c:334
void create_window(GdkGLConfig *glconfig, GtkWidget *vbox)
Definition gltemplate.c:363
static double len(glCompPoint p)
Definition glutils.c:150
int cb_glutinit(int w, int h, int *argcp, char *argv[], char *optArg)
Definition glutrender.c:226
void free(void *)
node NULL
Definition grammar.y:149
GtkWidget * gladewidget
Definition gui.c:23
GladeXML * xml
Definition gui.c:22
static const char * usage
Definition gvpr.c:53
static char * smyrnaGlade
Definition main.c:57
static char * Info[]
Definition main.c:97
char * smyrnaPath(char *suffix)
Definition main.c:68
static char * smyrnaDir
Definition main.c:56
static char * useString
Definition main.c:86
static char * readln(const char *path)
readlink-alike but dynamically allocates
Definition main.c:183
static char * find_me(void)
find an absolute path to the current executable
Definition main.c:215
static char * parseArgs(int argc, char *argv[], ViewInfo *viewinfo)
Definition main.c:103
static void windowedMode(int argc, char *argv[])
Definition main.c:139
static char * find_share(void)
find an absolute path to where Smyrna auxiliary files are stored
Definition main.c:314
void change_cursor(GdkCursorType C)
void mQuitSlot(GtkWidget *widget, gpointer user_data)
#define GUI_FULLSCREEN
Definition smyrnadefs.h:228
ViewInfo * view
Definition viewport.c:38
char * optArg
Definition smyrnadefs.h:372
GtkComboBox * graphComboBox
Definition smyrnadefs.h:364
char * initFileName
Definition smyrnadefs.h:359
int drawSplines
Definition smyrnadefs.h:361
Definition types.h:81
#define textdomain(String)
Definition support.h:23
#define bindtextdomain(Domain, Directory)
Definition support.h:27
int main()
void init_viewport(ViewInfo *vi)
Definition viewport.c:191