gbi.c 16.8 KB
Newer Older
1 2
/***************************************************************************

Benoît Minisini's avatar
Benoît Minisini committed
3
	gbi.c
4

Benoît Minisini's avatar
Benoît Minisini committed
5
	(c) 2000-2013 Benoît Minisini <gambas@users.sourceforge.net>
6

Benoît Minisini's avatar
Benoît Minisini committed
7 8 9 10
	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2, or (at your option)
	any later version.
11

Benoît Minisini's avatar
Benoît Minisini committed
12 13 14 15
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
16

Benoît Minisini's avatar
Benoît Minisini committed
17 18 19 20
	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
	MA 02110-1301, USA.
21 22 23

***************************************************************************/

Benoît Minisini's avatar
Benoît Minisini committed
24 25 26 27
#define __GBI_C

#include "config.h"
#include "trunk_version.h"
28 29 30 31 32 33 34 35 36 37 38 39 40 41

#include "gb_limit.h"
#include "gb_common.h"
#include "gb_alloc.h"

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include <sys/stat.h>
#include <sys/types.h>
42
#include <sys/wait.h>
43 44 45 46 47
#include <sys/time.h>
#include <dirent.h>

#include <dlfcn.h>

Benoît Minisini's avatar
Benoît Minisini committed
48
#if defined(OS_LINUX) || defined(OS_GNU) || defined(OS_OPENBSD) || defined(OS_FREEBSD) || defined(OS_CYGWIN)
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
	#define lt_dlinit() (0)
	#define lt_dlhandle void *
	#define lt_dlopenext(_path) dlopen(_path, RTLD_LAZY)
	#define lt_dlsym(_handle, _symbol) dlsym(_handle, _symbol)
	#define lt_dlclose(_handle) dlclose(_handle)
	#define lt_dlerror() dlerror()
#else
	#include <ltdl.h>
#endif

#include <ctype.h>

#include "gb_component.h"
#include "gb_file.h"
#include "gb_str.h"
#include "gb_arch.h"
#include "gb_common_swap.h"
66
#include "gb_array.h"
67
#include "gb_table.h"
68 69
#include "gambas.h"

Benoît Minisini's avatar
Benoît Minisini committed
70 71 72 73 74
static char _root[PATH_MAX + 1] = { 0 };
static char _lib_path[PATH_MAX + 1];
static char _info_path[PATH_MAX + 1];
static char _buffer[PATH_MAX + 1];
static char _env[PATH_MAX + 16];
75 76 77 78 79 80

static FILE *out_info;
static FILE *out_list;
static bool _verbose = FALSE;
static bool _format = FALSE;
static bool _nopreload = FALSE;
81
static bool _root_set = FALSE;
Benoît Minisini's avatar
Benoît Minisini committed
82
static bool _analyze = FALSE;
Benoît Minisini's avatar
Benoît Minisini committed
83
static bool _no_include_warning = TRUE;
84

85 86
static char **_components = NULL;

87 88
static TABLE *_classes = NULL;

89 90
static void analyze(const char *comp, bool include);

Benoît Minisini's avatar
Benoît Minisini committed
91
#if HAVE_GETOPT_LONG
92 93
static struct option LongOptions[] =
{
Benoît Minisini's avatar
Benoît Minisini committed
94 95 96
	{ "version", 0, NULL, 'V' },
	{ "verbose", 0, NULL, 'v' },
	{ "help", 0, NULL, 'h' },
97
	{ "license", 0, NULL, 'L' },
Benoît Minisini's avatar
Benoît Minisini committed
98 99
	{ "root", 1, NULL, 'r' },
	{ 0 }
100 101 102 103
};
#endif


104 105 106 107 108
static int compare_components(char **a, char **b)
{
	return strcmp(*a, *b);
}

109 110
static void print(const char *fmt, ...)
{
Benoît Minisini's avatar
Benoît Minisini committed
111
	va_list args;
112

Benoît Minisini's avatar
Benoît Minisini committed
113
	va_start(args, fmt);
114

Benoît Minisini's avatar
Benoît Minisini committed
115 116 117
	vfprintf(out_info, fmt, args);
	
	va_end(args);
118 119 120 121
}

static void warning(const char *fmt, ...)
{
Benoît Minisini's avatar
Benoît Minisini committed
122
	va_list args;
123 124 125

	fprintf(stderr, "gbi" GAMBAS_VERSION_STRING ": warning: ");
		
Benoît Minisini's avatar
Benoît Minisini committed
126
	va_start(args, fmt);
127

Benoît Minisini's avatar
Benoît Minisini committed
128 129 130 131 132
	vfprintf(stderr, fmt, args);
	
	putc('\n', stderr);
	
	va_end(args);
133 134 135 136
}

static void error(bool must_exit, const char *fmt, ...)
{
Benoît Minisini's avatar
Benoît Minisini committed
137
	va_list args;
138 139 140

	fprintf(stderr, "gbi" GAMBAS_VERSION_STRING ": ERROR: ");
		
Benoît Minisini's avatar
Benoît Minisini committed
141
	va_start(args, fmt);
142

Benoît Minisini's avatar
Benoît Minisini committed
143 144 145 146 147
	vfprintf(stderr, fmt, args);
	
	putc('\n', stderr);
	
	va_end(args);
148

Benoît Minisini's avatar
Benoît Minisini committed
149 150
	if (must_exit)
		exit(1);
151 152 153 154 155 156 157 158 159 160 161 162
}

// static void error2(const char *msg, const char *msg2, bool must_exit)
// {
//   fprintf(stderr, "gbi" GAMBAS_VERSION_STRING ": ERROR: %s: %s%s%s\n", msg, msg2, (errno != 0) ? ": " : "", (errno != 0) ? strerror(errno) : "");
//   if (must_exit)
//   	exit(1);
// }


static void init(void)
{
Benoît Minisini's avatar
Benoît Minisini committed
163
	const char *path;
Benoît Minisini's avatar
Benoît Minisini committed
164
	char *env;
165

Benoît Minisini's avatar
Benoît Minisini committed
166
	/* chemin d'installation de Gambas */
167

Benoît Minisini's avatar
Benoît Minisini committed
168 169
	if (!_root[0])
	{
Benoît Minisini's avatar
Benoît Minisini committed
170 171
		const char *dir;
		
Benoît Minisini's avatar
Benoît Minisini committed
172
		path = FILE_find_gambas();
Benoît Minisini's avatar
Benoît Minisini committed
173 174 175
		dir = FILE_get_dir(FILE_get_dir(path));
		if (dir)
			strncpy(_root, dir, PATH_MAX);
Benoît Minisini's avatar
Benoît Minisini committed
176
	}
177

Benoît Minisini's avatar
Benoît Minisini committed
178 179 180 181 182 183 184
	#ifdef OS_64BITS
	strcpy(_lib_path, FILE_cat(_root, GAMBAS_LIB64_PATH, NULL));
	if (access(FILE_cat(_lib_path, "gb.component", NULL), F_OK))
	#endif
		strcpy(_lib_path, FILE_cat(_root, GAMBAS_LIB_PATH, NULL));
		
	strcpy(_info_path, FILE_cat(_root, "share/gambas" GAMBAS_VERSION_STRING "/info", NULL));
185

Benoît Minisini's avatar
Benoît Minisini committed
186 187
	if (lt_dlinit())
		error(TRUE, "Cannot initialize plug-in management: %s", lt_dlerror());
188

Benoît Minisini's avatar
Benoît Minisini committed
189 190 191
	env = getenv("GBI_DEBUG");
	if (env && *env && atoi(env))
		_no_include_warning = FALSE;
192 193 194 195 196
}


static void newline()
{
Benoît Minisini's avatar
Benoît Minisini committed
197
	print("\n");
198 199 200 201 202
}

#if 0
static bool print_type(const char *type)
{
Benoît Minisini's avatar
Benoît Minisini committed
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
	switch (*type)
	{
		case 'b': print("Boolean"); break;
		case 'i': print("Integer"); break;
		case 's': print("String"); break;
		case 'd': print("Date"); break;
		case 'f': print("Float"); break;
		case 'v': print("Variant"); break;
		case 'o': print("Object"); break;

		default:

			while (*type && *type != ';')
			{
				print("%c", *type);
				type++;
			}
			return TRUE;
	}

	return FALSE;
224 225 226 227 228
}
#endif

static void dump_symbol(GB_DESC *desc)
{
Benoît Minisini's avatar
Benoît Minisini committed
229
	const char *name;
230
	const char *p;
231

Benoît Minisini's avatar
Benoît Minisini committed
232
	name = &desc->name[1];
233

Benoît Minisini's avatar
Benoît Minisini committed
234 235 236 237 238
	print("%s\n", name);
	print("%c\n", *desc->name);
	if (desc->val1)
		print("%s", desc->val1);
	newline();
239

Benoît Minisini's avatar
Benoît Minisini committed
240
	if (*desc->name == 'C')
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
	{
		switch(*(char *)desc->val1)
		{
			case 'i':
				print("%d", desc->val2);
				break;

			case 's':
				p = (const char *)desc->val2;
				while (*p)
				{
					if (*p == '\n')
						print("\\n");
					else if (*p == '\t')
						print("\\t");
					else
						print("%c", *p);
					p++;
				}
				break;
				
			case 'b':
263 264
				if (desc->val2)
					print("T");
265 266 267 268 269 270 271 272 273 274 275
				break;
				
			case 'f':
				print("%.15g", desc->val4);
				break;

			default:
				print("?");
				break;
		}
	}
Benoît Minisini's avatar
Benoît Minisini committed
276 277
	else if (desc->val3)
		print("%s", (char *)desc->val3);
278

Benoît Minisini's avatar
Benoît Minisini committed
279
	newline();
280 281 282 283 284 285 286
}


static GB_DESC *_sort_symbol;

static int sort_symbol(const int *a, const int *b)
{
Benoît Minisini's avatar
Benoît Minisini committed
287
	return strcmp(_sort_symbol[*a].name, _sort_symbol[*b].name);
288 289
}

290 291 292 293 294 295 296 297 298 299 300
static void add_class(const char *name)
{
	int index;

	if (out_list)
	{
		if (!TABLE_add_symbol(_classes, name, strlen(name), &index))
			fprintf(out_list, "%s\n", name);
	}
}

301 302
static void analyze_class(GB_DESC *desc)
{
Benoît Minisini's avatar
Benoît Minisini committed
303 304 305 306 307 308 309 310 311 312
	const char *name = desc->name;
	char *parent = NULL;
	bool autocreate = FALSE;
	bool nocreate = FALSE;
	uintptr_t hook;
	int nsymbol;
	int *sort;
	GB_DESC *p;
	int i;

313
	add_class(name);
Benoît Minisini's avatar
Benoît Minisini committed
314 315 316 317 318 319 320 321 322

	desc++;

	while (desc->name)
	{
		hook = (uintptr_t)desc->name;

		if (hook == (intptr_t)GB_INHERITS_ID)
			parent = (char *)desc->val1;
323
		else if (hook == (intptr_t)GB_NOT_CREATABLE_ID)
Benoît Minisini's avatar
Benoît Minisini committed
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
			nocreate = TRUE;
		else if (hook == (intptr_t)GB_AUTO_CREATABLE_ID)
			autocreate = TRUE;
		else if (hook > 16)
			break;

		desc++;
	}

	p = desc;
	nsymbol = 0;
	while (p->name)
	{
		nsymbol++;
		p++;
	}

	if (_format)
	{
		print("CLASS %s\n", name);
		if (parent) print("INHERITS %s\n", parent);
		if (!nocreate) print("CREATABLE\n");
		if (autocreate) print("AUTOCREATABLE\n");
	}
	else
	{
		print("#%s\n", name);
		if (parent)
			print("%s", parent);
		newline();
		if (!nocreate)
			print("C");
		if (autocreate)
			print("A");
		newline();
	}

Benoît Minisini's avatar
Benoît Minisini committed
361
	ALLOC(&sort, sizeof(int) * nsymbol);
Benoît Minisini's avatar
Benoît Minisini committed
362 363 364 365 366 367 368 369 370
	for (i = 0; i < nsymbol; i++)
		sort[i] = i;
	
	_sort_symbol = desc;
	qsort(sort, nsymbol, sizeof(int), (int (*)(const void *, const void *))sort_symbol);

	for (i = 0; i < nsymbol; i++)
		dump_symbol(&desc[sort[i]]);

Benoît Minisini's avatar
Benoît Minisini committed
371
	FREE(&sort);
Benoît Minisini's avatar
Benoît Minisini committed
372 373 374
	
	if (_format)
		newline();
375 376 377 378 379 380 381
}


static GB_DESC **_sort_desc;

static int sort_desc(const int *a, const int *b)
{
Benoît Minisini's avatar
Benoît Minisini committed
382
	return strcmp(_sort_desc[*a]->name, _sort_desc[*b]->name);
383 384
}

385 386 387 388 389 390 391 392 393 394 395 396
static void analyze_include(char *include_list)
{
	char *includes[8];
	int nincludes;
	char *include;
	int i;
	
	include_list = STR_copy(include_list);
	
	if (_verbose)
		fprintf(stderr, "Including %s\n", include_list);
	
397
	nincludes = 0;
398 399 400 401 402 403 404 405 406 407 408 409 410
	include = strtok(include_list, ",");
	while (include && nincludes < 8)
	{
		includes[nincludes++] = include;
		include = strtok(NULL, ",");
	}
	
	for (i = 0; i < nincludes; i++)
		analyze(includes[i], TRUE);
		
	STR_free(include_list);
}

411 412
static bool analyze_native_component(const char *path)
{
Benoît Minisini's avatar
Benoît Minisini committed
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
	lt_dlhandle lib;
	GB_DESC **desc;
	char **include;
	GB_DESC **p;
	bool ret = FALSE;
	int nclass;
	int *sort;
	int i;

	if (_verbose)
		fprintf(stderr, "Loading native component: %s\n", path);

	//lt_dlopen_flag = RTLD_LAZY; /* | RTLD_GLOBAL;*/

	lib = lt_dlopenext(path);
	if (!lib)
	{
		error(FALSE, "Cannot load shared library: %s", lt_dlerror());
		return TRUE;
432 433 434 435
	}

	include = lt_dlsym(lib, LIB_INCLUDE);
	if (include)
436
		analyze_include(*include);
437

Benoît Minisini's avatar
Benoît Minisini committed
438 439 440 441 442 443 444 445 446 447 448 449
	desc = lt_dlsym(lib, LIB_CLASS);

	if (desc)
	{
		p = desc;
		nclass = 0;
		while (*p)
		{
			nclass++;
			p++;
		}
	
Benoît Minisini's avatar
Benoît Minisini committed
450
		ALLOC(&sort, sizeof(int) * nclass);
Benoît Minisini's avatar
Benoît Minisini committed
451 452 453 454 455 456 457 458 459
		for (i = 0; i < nclass; i++)
			sort[i] = i;
		
		_sort_desc = desc;
		qsort(sort, nclass, sizeof(int), (int (*)(const void *, const void *))sort_desc);
	
		for (i = 0; i < nclass; i++)
			analyze_class(desc[sort[i]]);
			
Benoît Minisini's avatar
Benoît Minisini committed
460
		FREE(&sort);
Benoît Minisini's avatar
Benoît Minisini committed
461 462 463 464 465 466
	}
	else
	{
		if (_verbose)
			warning("cannot find '" LIB_CLASS "' symbol in shared library.");
		//ret = TRUE;
467 468
	}

469
	// Do not close shared libraries, except on openbsd that seems to feel better with
470 471 472
	#ifdef OS_OPENBSD
	lt_dlclose(lib);
	#endif
473

Benoît Minisini's avatar
Benoît Minisini committed
474
	return ret;
475 476 477 478 479
}


static bool analyze_gambas_component(const char *path)
{
Benoît Minisini's avatar
Benoît Minisini committed
480 481
	ARCH *arch;
	ARCH_FIND find;
482
	bool ret = TRUE;
483 484
	char *buffer;
	char *line;
485

Benoît Minisini's avatar
Benoît Minisini committed
486 487
	if (_verbose)
		fprintf(stderr, "Loading gambas component: %s\n", path);
488

Benoît Minisini's avatar
Benoît Minisini committed
489
	arch = ARCH_open(path);
490

491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
	if (!ARCH_find(arch, ".component", 0, &find))
	{
		ALLOC(&buffer, find.len + 1);
		memcpy(buffer, &arch->addr[find.pos], find.len);
		buffer[find.len] = 0;

		for (line = strtok(buffer, "\n"); line; line = strtok(NULL, "\n"))
		{
			if (strncmp(line, "Include=", 8))
				continue;
			analyze_include(&line[8]);
			break;
		}

		FREE(&buffer);
	}

Benoît Minisini's avatar
Benoît Minisini committed
508 509
	if (ARCH_find(arch, ".info", 0, &find))
	{
510
		warning("'.info' file not found in component archive.");
511
		goto __RETURN;
512 513
	}

Benoît Minisini's avatar
Benoît Minisini committed
514
	fwrite(&arch->addr[find.pos], 1, find.len, out_info);
515

Benoît Minisini's avatar
Benoît Minisini committed
516 517
	if (ARCH_find(arch, ".list", 0, &find))
	{
518
		warning("'.list' file not found in component archive.");
519
		goto __RETURN;
520 521
	}

522 523 524
	ALLOC(&buffer, find.len + 1);
	memcpy(buffer, &arch->addr[find.pos], find.len);
	buffer[find.len] = 0;
525

526 527
	for (line = strtok(buffer, "\n"); line; line = strtok(NULL, "\n"))
		add_class(line);
528

529
	FREE(&buffer);
530 531

	//fwrite(&arch->addr[find.pos], 1, find.len, out_list);
532
	ret = FALSE;
533

534 535
__RETURN:
	
Benoît Minisini's avatar
Benoît Minisini committed
536
	ARCH_close(arch);
537
	return ret;
538 539
}

Benoît Minisini's avatar
Benoît Minisini committed
540
#if 0
541 542 543
static void preload(char **argv, char *lib)
{
#if DO_PRELOADING
Benoît Minisini's avatar
Benoît Minisini committed
544 545
	if (_nopreload || getenv("GB_PRELOAD") || !lib || !*lib)
		return;
546

Benoît Minisini's avatar
Benoît Minisini committed
547 548 549
	snprintf(_env, sizeof(_env), "LD_PRELOAD=%s", lib);
	putenv(_env);
	putenv("GB_PRELOAD=1");
550

Benoît Minisini's avatar
Benoît Minisini committed
551
	execvp(argv[0], argv);
552 553
#endif
}
Benoît Minisini's avatar
Benoît Minisini committed
554
#endif
555

Benoît Minisini's avatar
Benoît Minisini committed
556 557 558 559 560
static bool find_native_component(const char *name)
{
	snprintf(_buffer, sizeof(_buffer), LIB_PATTERN, _lib_path, name);
	return (access(_buffer, F_OK) == 0);
}
561 562 563

static void analyze(const char *comp, bool include)
{
Benoît Minisini's avatar
Benoît Minisini committed
564 565 566 567 568
	bool native, gambas;
	char *name;
	char *path_list = NULL;
	char *path_info = NULL;
	bool ok;
569

Benoît Minisini's avatar
Benoît Minisini committed
570
	name = STR_copy(comp);
571

572 573
	if (_verbose)
		fprintf(stderr, "%s component %s\n", include ? "Including" : "Analyzing", name);
Benoît Minisini's avatar
Benoît Minisini committed
574
	else if (!include)
575 576
		puts(name);
	
Benoît Minisini's avatar
Benoît Minisini committed
577
	native = find_native_component(name);
578
		
Benoît Minisini's avatar
Benoît Minisini committed
579 580 581 582 583
	snprintf(_buffer, sizeof(_buffer), ARCH_PATTERN, _lib_path, name);
	gambas = (access(_buffer, F_OK) == 0);

	if (!native && !gambas)
	{
Benoît Minisini's avatar
Benoît Minisini committed
584 585
		if (!include || !_no_include_warning)
			warning("component %s not found", name);
Benoît Minisini's avatar
Benoît Minisini committed
586 587 588 589 590 591
		STR_free(name);
		return;
	}

	if (!include)
	{
592 593 594 595 596
		path_info = STR_cat(FILE_cat(_info_path, name, NULL), ".info", NULL);
		path_list = STR_cat(FILE_cat(_info_path, name, NULL), ".list", NULL);
	
		out_info = fopen(path_info, "w");
		if (!out_info)
Benoît Minisini's avatar
Benoît Minisini committed
597 598 599 600
		{
			error(FALSE, "Cannot write file: %s", path_info);
			return;
		}
601 602 603
	
		out_list = fopen(path_list, "w");
		if (!out_list)
Benoît Minisini's avatar
Benoît Minisini committed
604 605 606 607
		{
			error(FALSE, "Cannot write file: %s", path_list);
			return;
		}
608 609

		TABLE_create(&_classes, sizeof(SYMBOL), TF_IGNORE_CASE);
610 611
	}
	
Benoît Minisini's avatar
Benoît Minisini committed
612 613
	fflush(stdout);
	ok = TRUE;
614

615

Benoît Minisini's avatar
Benoît Minisini committed
616 617 618
	if (native)
	{
		snprintf(_buffer, sizeof(_buffer), LIB_PATTERN, _lib_path, name);
619

Benoît Minisini's avatar
Benoît Minisini committed
620 621 622
		if (analyze_native_component(_buffer))
			ok = FALSE;
	}
623

Benoît Minisini's avatar
Benoît Minisini committed
624 625 626
	if (gambas)
	{
		snprintf(_buffer, sizeof(_buffer), ARCH_PATTERN, _lib_path, name);
627

Benoît Minisini's avatar
Benoît Minisini committed
628 629 630 631
		if (analyze_gambas_component(_buffer))
			if (!native)
				ok = FALSE;
	}
632 633 634

	if (!include)
	{
635 636
		TABLE_delete(&_classes);

637 638 639 640 641
		fclose(out_info);
		fclose(out_list);
	
		if (!ok)
		{
Benoît Minisini's avatar
Benoît Minisini committed
642 643
			FILE_unlink(path_info);
			FILE_unlink(path_list);
644
		}
Benoît Minisini's avatar
Benoît Minisini committed
645 646
		else if (_verbose)
		{
647 648
			fprintf(stderr, "Wrote %s\n", path_info);
			fprintf(stderr, "Wrote %s\n", path_list);
Benoît Minisini's avatar
Benoît Minisini committed
649
		}
650 651 652 653 654

		STR_free(path_info);
		STR_free(path_list);
	}
	
Benoît Minisini's avatar
Benoît Minisini committed
655
	STR_free(name);
656 657
}

658 659 660 661 662 663 664
static void run_myself(const char *path, const char *name)
{
	const char *argv[10];
	int n = 0;
	pid_t pid;
	int status;
	
665 666 667
	if (_verbose)
		fprintf(stderr, "Running myself for component %s\n", name);
	
668 669 670 671 672 673 674 675 676 677
	argv[n++] = path;
	if (_verbose)
		argv[n++] = "-v";
	if (_nopreload)
		argv[n++] = "-p";
	if (_root_set)
	{
		argv[n++] = "-r";
		argv[n++] = _root;
	}
Benoît Minisini's avatar
Benoît Minisini committed
678
	argv[n++] = "-a";
679 680 681
	argv[n++] = name;
	argv[n] = NULL;
	
Benoît Minisini's avatar
Benoît Minisini committed
682 683 684 685 686 687
	if (find_native_component(name))
	{
		snprintf(_env, sizeof(_env), "LD_PRELOAD=%s", _buffer);
		putenv(_env);
	}

688 689 690 691
	pid = fork();
	switch (pid)
	{
		case 0:
Benoît Minisini's avatar
Benoît Minisini committed
692
			execvp(path, (char **)argv);
Benoît Minisini's avatar
Benoît Minisini committed
693 694
			error(FALSE, "Cannot run sub-process: %s", strerror(errno));
			exit(1);
695
		case -1:
Benoît Minisini's avatar
Benoît Minisini committed
696 697 698 699
			error(FALSE, "Cannot run sub-process: %s", strerror(errno));
			exit(1);
		default:
			waitpid(pid, &status, 0);
700 701
	}
}
702

703
static void make_component_list()
704
{
Benoît Minisini's avatar
Benoît Minisini committed
705 706 707
	DIR *dir;
	struct dirent *dirent;
	const char *name;
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
			
	dir = opendir(_lib_path);
	if (dir == NULL)
		error(TRUE, "Cannot read directory: %s", _lib_path);

	//save_fd = dup(STDOUT_FILENO);

	ARRAY_create(&_components);
	
	while ((dirent = readdir(dir)) != NULL)
	{
		name = dirent->d_name;
		if (strcmp(FILE_get_ext(name), "component"))
			continue;
		name = FILE_get_basename(name);
		*((char **)ARRAY_add(&_components)) = STR_copy(name);
	}

	closedir(dir);
	
	qsort(_components, ARRAY_count(_components), sizeof(*_components), (int (*)(const void *, const void *))compare_components);
}

int main(int argc, char **argv)
{
	int i;
	char *name;
Benoît Minisini's avatar
Benoît Minisini committed
735 736 737 738 739 740 741 742 743
	int opt;
	int ind = 0;

	/*#ifdef __FreeBSD__
	optind = 1;
	#else
	optind = 0;
	#endif*/

Benoît Minisini's avatar
Benoît Minisini committed
744
	//dup(STDOUT_FILENO);
745

746
	//_verbose = TRUE;
Benoît Minisini's avatar
Benoît Minisini committed
747

Benoît Minisini's avatar
Benoît Minisini committed
748 749
	for(;;)
	{
Benoît Minisini's avatar
Benoît Minisini committed
750
		#if HAVE_GETOPT_LONG
751
			opt = getopt_long(argc, argv, "vVhLpar:", LongOptions, &ind);
Benoît Minisini's avatar
Benoît Minisini committed
752
		#else
753
			opt = getopt(argc, argv, "vVhLpar:");
Benoît Minisini's avatar
Benoît Minisini committed
754 755 756 757 758 759
		#endif
		if (opt < 0) break;

		switch (opt)
		{
			case 'V':
Benoît Minisini's avatar
Benoît Minisini committed
760 761 762
				#ifdef TRUNK_VERSION
				printf(VERSION " r" TRUNK_VERSION "\n");
				#else
Benoît Minisini's avatar
Benoît Minisini committed
763
				printf(VERSION "\n");
Benoît Minisini's avatar
Benoît Minisini committed
764
				#endif
Benoît Minisini's avatar
Benoît Minisini committed
765 766 767 768 769
				exit(0);

			case 'v':
				_verbose = TRUE;
				break;
Benoît Minisini's avatar
Benoît Minisini committed
770
#if DO_PRELOADING
Benoît Minisini's avatar
Benoît Minisini committed
771 772 773
			case 'p':
				_nopreload = TRUE;
				break;
Benoît Minisini's avatar
Benoît Minisini committed
774 775
#endif
				
Benoît Minisini's avatar
Benoît Minisini committed
776
			case 'r':
Benoît Minisini's avatar
Benoît Minisini committed
777
				strncpy(_root, optarg, PATH_MAX);
Benoît Minisini's avatar
Benoît Minisini committed
778 779 780 781 782 783
				_root_set = TRUE;
				break;
				
			case 'a':
				_analyze = TRUE;
				break;
784 785
				
			case 'L':
Benoît Minisini's avatar
Benoît Minisini committed
786
				printf(
Benoît Minisini's avatar
Benoît Minisini committed
787
					"\nGAMBAS Component Informer version " VERSION " " __DATE__ " " __TIME__ "\n"
Benoît Minisini's avatar
Benoît Minisini committed
788
					COPYRIGHT
789 790 791 792 793
					);
				exit(0);

			case 'h':
				printf(
Benoît Minisini's avatar
Benoît Minisini committed
794 795
					"\nGenerate component description files.\n"
					"\nUsage: gbi" GAMBAS_VERSION_STRING " [options] [components]\n"
Benoît Minisini's avatar
Benoît Minisini committed
796
					"\nOptions:"
Benoît Minisini's avatar
Benoît Minisini committed
797
					#if HAVE_GETOPT_LONG
Benoît Minisini's avatar
Benoît Minisini committed
798
					"\n"
Benoît Minisini's avatar
Benoît Minisini committed
799
					#if DO_PRELOADING
Benoît Minisini's avatar
Benoît Minisini committed
800
					"  -p                         disable preloading\n"
Benoît Minisini's avatar
Benoît Minisini committed
801
					#endif
Benoît Minisini's avatar
Benoît Minisini committed
802
					"  -r  --root <directory>     gives the gambas installation directory\n"
Benoît Minisini's avatar
Benoît Minisini committed
803 804 805
					"  -V  --version              display version\n"
					"  -L  --license              display license\n"
					"  -h  --help                 display this help\n"
Benoît Minisini's avatar
Benoît Minisini committed
806 807
					#else
					" (no long options on this system)\n"
Benoît Minisini's avatar
Benoît Minisini committed
808
					#if DO_PRELOADING
Benoît Minisini's avatar
Benoît Minisini committed
809
					"  -p                         disable preloading\n"
Benoît Minisini's avatar
Benoît Minisini committed
810
					#endif
Benoît Minisini's avatar
Benoît Minisini committed
811
					"  -r <directory>             gives the gambas installation directory\n"
Benoît Minisini's avatar
Benoît Minisini committed
812 813 814
					"  -V                         display version\n"
					"  -L                         display license\n"
					"  -h                         display this help\n"
Benoît Minisini's avatar
Benoît Minisini committed
815 816 817 818 819 820 821 822 823 824 825 826 827
					#endif
					"\n"
					);

				exit(0);
		}
	}

	init();
	
	if (_analyze)
	{
		if (_verbose)
828 829 830 831 832
		{
			char *env = getenv("LD_PRELOAD");
			if (env)
				fprintf(stderr, "LD_PRELOAD=%s\n", env);
		}
Benoît Minisini's avatar
Benoît Minisini committed
833 834

		analyze(argv[optind], FALSE);
Benoît Minisini's avatar
Benoît Minisini committed
835 836 837 838
		/*if (strcmp(argv[optind], "gb.qt4") == 0)
			analyze("gb.gui", FALSE);
		else if (strcmp(argv[optind], "gb.qt4.opengl") == 0)
			analyze("gb.gui.opengl", FALSE);*/
Benoît Minisini's avatar
Benoît Minisini committed
839 840 841 842 843 844 845 846 847
	}
	else
	{
		if (optind == argc
		#ifdef OS_SOLARIS  /* solaris bug ? */
				|| optind == 0
		#endif
				)
		{
Benoît Minisini's avatar
Benoît Minisini committed
848
			/*preload(argv,
Benoît Minisini's avatar
Benoît Minisini committed
849 850
				"libqt-mt.so.3 "
				"libkdecore.so.4 "
Benoît Minisini's avatar
Benoît Minisini committed
851
				);*/
Benoît Minisini's avatar
Benoît Minisini committed
852 853 854 855 856 857
	
			if (_verbose)
			{
				fprintf(stderr, "component path: %s\n", _lib_path);
				fprintf(stderr, "info path: %s\n", _info_path);
			}
858 859 860 861
			
			make_component_list();
			
			for (i = 0; i < ARRAY_count(_components); i++)
862
			{
863
				name = _components[i];
Benoît Minisini's avatar
Benoît Minisini committed
864
				run_myself(argv[0], name);
865
				STR_free(name);
866
			}
867
			
Benoît Minisini's avatar
Benoît Minisini committed
868
			ARRAY_delete(&_components);
869
		}
Benoît Minisini's avatar
Benoît Minisini committed
870 871
		else
		{
Benoît Minisini's avatar
Benoît Minisini committed
872
			if (!getenv("GB_PRELOAD"))
Benoît Minisini's avatar
Benoît Minisini committed
873 874 875 876
			{
				for (ind = optind; ind < argc; ind++)
				{
					name = argv[ind];			
Benoît Minisini's avatar
Benoît Minisini committed
877
					/*if (strncmp(name, "gb.qt.kde", 9) == 0)
Benoît Minisini's avatar
Benoît Minisini committed
878 879
						preload(argv, "libqt-mt.so.3 libkdecore.so.4");
					else if (strcmp(name, "gb.qt") == 0 || strncmp(name, "gb.qt.", 6) == 0)
Benoît Minisini's avatar
Benoît Minisini committed
880
						preload(argv, "libqt-mt.so.3");*/
Benoît Minisini's avatar
Benoît Minisini committed
881 882 883 884 885 886 887 888 889
				}
			}
		
			for (ind = optind; ind < argc; ind++)
			{
				name = argv[ind];
				//analyze(name, FALSE);
				run_myself(argv[0], name);
			}
890
		}
Benoît Minisini's avatar
Benoît Minisini committed
891
	}
892

Benoît Minisini's avatar
Benoît Minisini committed
893
	exit(0);
894 895
}