1 /*
2 Copyright (C) 2009  Justin Karneges
3 
4 This file is free software; unlimited permission is given to copy and/or
5 distribute it, with or without modifications, as long as this notice is
6 preserved.
7 */
8 
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <errno.h>
15 //#include <unistd.h>
16 #include <limits.h>
17 #include "embed.h"
18 
19 #if defined(WIN32) || defined(_WIN32)
20 # define QC_OS_WIN
21 #endif
22 
23 #ifdef QC_OS_WIN
24 #include <direct.h>
25 #endif
26 
27 #ifdef QC_OS_WIN
28 static char *qconftemp_path = "qconftemp";
29 static char path_separator = ';';
30 #else
31 static char *qconftemp_path = ".qconftemp";
32 static char path_separator = ':';
33 #endif
34 
35 static int qc_verbose = 0;
36 static char *ex_qtdir = NULL;
37 static char *qc_qtselect = NULL;
38 static char *qtsearchtext="4 or 5";
39 
40 static char *prefix = NULL;
41 static char *bindir = NULL;
42 static char *includedir = NULL;
43 static char *libdir = NULL;
44 static char *datadir = NULL;
45 
46 static int run_buffer_stdout(const char *command, char *out_buf, size_t buf_size);
47 
48 enum ArgType
49 {
50 	ArgValue,
51 	ArgFlag
52 };
53 
54 typedef struct qcarg
55 {
56 	char *name;
57 	char *envvar;
58 	int type;
59 	char *val; // we populate this later based on actual passed args
60 } qcarg_t;
61 
62 typedef struct qcfile
63 {
64 	char *name;
65 	unsigned char *data;
66 	unsigned int size;
67 } qcfile_t;
68 
69 typedef struct qcdata
70 {
71 	char *usage;
72 
73 	qcarg_t *args;
74 	int args_count;
75 
76 	qcfile_t *files;
77 	int files_count;
78 
79 	char *pro_name;
80 	char *pro_file;
81 
82 	char *qtinfo;
83 } qcdata_t;
84 
alloc_str(const unsigned char * src,int len)85 static char *alloc_str(const unsigned char *src, int len)
86 {
87 	char *out;
88 	out = (char *)malloc(len + 1);
89 	memcpy(out, src, len);
90 	out[len] = 0;
91 	return out;
92 }
93 
index_of(const char * in,char sub)94 static int index_of(const char *in, char sub)
95 {
96 	int n;
97 	for(n = 0; in[n]; ++n)
98 	{
99 		if(in[n] == sub)
100 			return n;
101 	}
102 	return -1;
103 }
104 
index_of_str(const char * in,const char * sub)105 static int index_of_str(const char *in, const char *sub)
106 {
107 	char *p;
108 	p = strstr(in, sub);
109 	if(p)
110 		return p - in;
111 	else
112 		return -1;
113 }
114 
selection_insert(const char * in,int at,int len,const char * sub)115 static char *selection_insert(const char *in, int at, int len, const char *sub)
116 {
117 	int ilen;
118 	int slen;
119 	int newsize;
120 	char *out;
121 
122 	ilen = strlen(in);
123 	slen = strlen(sub);
124 	newsize = ilen - len + slen;
125 	out = (char *)malloc(newsize + 1);
126 	memcpy(out, in, at);
127 	memcpy(out + at, sub, slen);
128 	memcpy(out + at + slen, in + at + len, ilen - at - len);
129 	out[newsize] = 0;
130 
131 	return out;
132 }
133 
find_replace(const char * in,const char * old,const char * newv)134 static char *find_replace(const char *in, const char *old, const char *newv)
135 {
136 	int at;
137 	int olen;
138 
139 	olen = strlen(old);
140 	at = index_of_str(in, old);
141 	if(at != -1)
142 		return selection_insert(in, at, olen, newv);
143 	else
144 		return strdup(in);
145 }
146 
append_str(const char * in,const char * add)147 static char *append_str(const char *in, const char *add)
148 {
149 	return selection_insert(in, strlen(in), 0, add);
150 }
151 
152 // creates new string and frees old
append_free(char * in,const char * add)153 static char *append_free(char *in, const char *add)
154 {
155 	char *out;
156 	out = append_str(in, add);
157 	free(in);
158 	return out;
159 }
160 
161 // FIXME: handle bad data, don't malloc 0, etc
parse_data(unsigned char * data,unsigned int size)162 static qcdata_t *parse_data(unsigned char *data, unsigned int size)
163 {
164 	unsigned char *p;
165 	qcdata_t *q;
166 	unsigned int len;
167 	int n;
168 
169 	(void)size;
170 
171 	q = (qcdata_t *)malloc(sizeof(qcdata_t));
172 	p = data;
173 	len = read32(p);
174 	p += 4;
175 	q->usage = alloc_str(p, len);
176 	p += len;
177 
178 	q->args_count = read32(p);
179 	p += 4;
180 	q->args = (qcarg_t *)malloc(sizeof(qcarg_t) * q->args_count);
181 	for(n = 0; n < q->args_count; ++n)
182 	{
183 		len = read32(p);
184 		p += 4;
185 		q->args[n].name = alloc_str(p, len);
186 		p += len;
187 
188 		len = read32(p);
189 		p += 4;
190 		q->args[n].envvar = alloc_str(p, len);
191 		p += len;
192 
193 		q->args[n].type = *(p++);
194 
195 		q->args[n].val = NULL;
196 	}
197 
198 	q->files_count = read32(p);
199 	p += 4;
200 	q->files = (qcfile_t *)malloc(sizeof(qcfile_t) * q->files_count);
201 	for(n = 0; n < q->files_count; ++n)
202 	{
203 		len = read32(p);
204 		p += 4;
205 		q->files[n].name = alloc_str(p, len);
206 		p += len;
207 
208 		len = read32(p);
209 		p += 4;
210 		q->files[n].data = (unsigned char *)malloc(len);
211 		memcpy(q->files[n].data, p, len);
212 		q->files[n].size = len;
213 		p += len;
214 	}
215 
216 	len = read32(p);
217 	p += 4;
218 	q->pro_name = alloc_str(p, len);
219 	p += len;
220 
221 	len = read32(p);
222 	p += 4;
223 	q->pro_file = alloc_str(p, len);
224 	p += len;
225 
226 	len = read32(p);
227 	p += 4;
228 	q->qtinfo = alloc_str(p, len);
229 	p += len;
230 
231 	return q;
232 }
233 
qcdata_delete(qcdata_t * q)234 static void qcdata_delete(qcdata_t *q)
235 {
236 	int n;
237 
238 	if(q->usage)
239 		free(q->usage);
240 
241 	for(n = 0; n < q->args_count; ++n)
242 	{
243 		free(q->args[n].name);
244 		free(q->args[n].envvar);
245 		if(q->args[n].val)
246 			free(q->args[n].val);
247 	}
248 
249 	for(n = 0; n < q->files_count; ++n)
250 	{
251 		free(q->files[n].name);
252 		free(q->files[n].data);
253 	}
254 
255 	if(q->pro_name)
256 		free(q->pro_name);
257 	if(q->pro_file)
258 		free(q->pro_file);
259 
260 	free(q);
261 }
262 
find_arg(const qcarg_t * args,int count,const char * name)263 static int find_arg(const qcarg_t *args, int count, const char *name)
264 {
265 	int n;
266 	for(n = 0; n < count; ++n)
267 	{
268 		if(strcmp(args[n].name, name) == 0)
269 			return n;
270 	}
271 	return -1;
272 }
273 
find_file(const qcfile_t * files,int count,const char * name)274 static int find_file(const qcfile_t *files, int count, const char *name)
275 {
276 	int n;
277 	for(n = 0; n < count; ++n)
278 	{
279 		if(strcmp(files[n].name, name) == 0)
280 			return n;
281 	}
282 	return -1;
283 }
284 
285 // adapted from qt
set_envvar(const char * var,const char * val)286 static int set_envvar(const char *var, const char *val)
287 {
288 #if defined(_MSC_VER) && _MSC_VER >= 1400
289 	return (_putenv_s(var, val) == 0 ? 1 : 0);
290 #else
291 	char *str;
292 	str = malloc(strlen(var) + 1 + strlen(val) + 1);
293 	strcpy(str, var);
294 	strcat(str, "=");
295 	strcat(str, val);
296 	return (putenv(str) == 0 ? 1 : 0);
297 #endif
298 }
299 
get_envvar(const char * var)300 static char *get_envvar(const char *var)
301 {
302 	return getenv(var);
303 }
304 
separators_to_native(const char * in)305 static char *separators_to_native(const char *in)
306 {
307 	char *out;
308 
309 #ifdef QC_OS_WIN
310 	int len;
311 	int n;
312 
313 	out = strdup(in);
314 	len = strlen(in);
315 	for(n = 0; n < len; ++n)
316 	{
317 		if(out[n] == '/')
318 			out[n] = '\\';
319 	}
320 #else
321 	out = strdup(in);
322 #endif
323 
324 	return out;
325 }
326 
file_exists(const char * path)327 static int file_exists(const char *path)
328 {
329 	char *npath;
330 	int ret;
331 #ifdef QC_OS_WIN
332 	struct _stat buf;
333 #else
334 	struct stat buf;
335 #endif
336 
337 	npath = separators_to_native(path);
338 
339 #ifdef QC_OS_WIN
340 	ret = _stat(npath, &buf);
341 #else
342 	ret = stat(npath, &buf);
343 #endif
344 
345 	free(npath);
346 	if(ret == 0)
347 		return 1;
348 	else
349 		return 0;
350 }
351 
check_qmake_path(const char * qtdir)352 static char *check_qmake_path(const char *qtdir)
353 {
354 	char *str;
355 
356 	str = separators_to_native(qtdir);
357 #ifdef QC_OS_WIN
358 	str = append_free(str, "\\qmake.exe");
359 #else
360 	str = append_free(str, "/qmake");
361 #endif
362 	if (qc_verbose) {
363 		printf("Check if \"%s\" exists\n", str);
364 	}
365 	if(file_exists(str))
366 	{
367 		return str;
368 	}
369 	else
370 	{
371 		free(str);
372 		return NULL;
373 	}
374 }
375 
qmake_query(const char * qmake_path,const char * var,char * out_buf,size_t buf_size)376 static int qmake_query(const char *qmake_path, const char *var, char *out_buf, size_t buf_size)
377 {
378 	char command[PATH_MAX];
379 	int cnt = snprintf(command, sizeof(command) - 1, "%s -query %s", qmake_path, var);
380 	if (cnt > 0 && cnt < (int)sizeof(command))
381 	{
382 		command[sizeof(command) - 1] = '\0'; // To be sure line has null-terminator
383 		return run_buffer_stdout(command, out_buf, buf_size);
384 	}
385 	return 0; // fail
386 }
387 
qmake_query_maj_ver(const char * qmake_path,char * out_buf,size_t buf_size)388 static int qmake_query_maj_ver(const char *qmake_path, char *out_buf, size_t buf_size)
389 {
390 	if (qmake_query(qmake_path, "QT_VERSION", out_buf, buf_size)) {
391 		int at = index_of(out_buf, '.');
392 		if (at > 0)
393 		{
394 			out_buf[at] = '\0';
395 			return 1;
396 		}
397 	}
398 	return 0;
399 }
400 
401 // modifies contents of spec_path and returns pointer to spec name
extract_spec_name(char * spec_path)402 char *extract_spec_name(char *spec_path)
403 {
404 	char *end = spec_path;
405 	while (!iscntrl(*end)) {
406 		if (*end == '/') {
407 			if (iscntrl(*(end+1))) { // next is end of line
408 				break;
409 			} else {
410 				spec_path = end + 1;
411 				end = spec_path + 1;
412 			}
413 		} else
414 			end++;
415 	}
416 	*end = 0;
417 	return spec_path;
418 }
419 
check_qtversion(char * path,char * version)420 int check_qtversion(char *path, char *version)
421 {
422 	int res = 0;
423 
424 	if (version)
425 	{
426 		char buf[20]; // version string output always small
427 		if (qmake_query_maj_ver(path, buf, sizeof(buf))) {
428 			res = !strcmp(version, buf);
429 			if (!res && qc_verbose)
430 			{
431 				printf("Warning: %s not for Qt %s\n", path, qtsearchtext);
432 			}
433 		}
434 	}
435 	else
436 	{
437 		res = 1;
438 	}
439 
440 	return res;
441 }
442 
parse_qtselect(char * src)443 static char* parse_qtselect(char *src)
444 {
445 	unsigned long int ver;
446 	if (src) {
447 		if (src[0] == 'q' && src[1] == 't')
448 			src += 2;
449 
450 		ver = strtoul(src, NULL, 10);
451 		if (ver > 0 && ver < ULONG_MAX) {
452 			qc_qtselect = strdup(src);
453 			qtsearchtext = qc_qtselect;
454 			return qc_qtselect;
455 		}
456 	}
457 	return NULL;
458 }
459 
find_qmake()460 static char *find_qmake()
461 {
462 	char *qtdir;
463 	char *path;
464 	char try_syspath = 1;
465 
466 	if (!qc_qtselect)
467 		parse_qtselect(get_envvar("QT_SELECT"));
468 
469 
470 	qtdir = ex_qtdir;
471 	if(qtdir)
472 	{
473 		qtdir = append_free(strdup(qtdir), "\\bin");
474 		path = check_qmake_path(qtdir);
475 		free(qtdir);
476 
477 		if(path)
478 		{
479 			if (!check_qtversion(path, qc_qtselect))
480 				return NULL;
481 			return path;
482 		}
483 		try_syspath = 0;
484 	}
485 	if(qc_verbose)
486 		printf("Warning: qmake not found via --qtdir\n");
487 
488 	qtdir = get_envvar("QTDIR");
489 	if(qtdir)
490 	{
491 		qtdir = append_free(strdup(qtdir), "\\bin");
492 		path = check_qmake_path(qtdir);
493 		free(qtdir);
494 
495 		if(path)
496 		{
497 			if (!check_qtversion(path, qc_qtselect))
498 				return NULL;
499 			return path;
500 		}
501 		try_syspath = 0;
502 	}
503 	if(qc_verbose)
504 		printf("Warning: qmake not found via %%QTDIR%%\n");
505 
506 	/* if not set explicitly try something implicit */
507 	if (try_syspath) {
508 		char *paths = strdup(get_envvar("PATH"));
509 		qtdir = paths;
510 		while (1)
511 		{
512 			int at = index_of(qtdir, path_separator);
513 			if (at > 0)
514 				qtdir[at] = '\0';
515 			path = check_qmake_path(qtdir);
516 			if (path && check_qtversion(path, qc_qtselect))
517 			{
518 				free(paths);
519 				return path;
520 			}
521 
522 			if (at > 0)
523 				qtdir += at + 1;
524 			else
525 				break;
526 		}
527 		free(paths);
528 	}
529 
530 	if(qc_verbose)
531 		printf("Warning: qmake not found in PATH\n");
532 
533 	return NULL;
534 }
535 
run_buffer_stdout(const char * command,char * out_buf,size_t buf_size)536 static int run_buffer_stdout(const char *command, char *out_buf, size_t buf_size)
537 {
538 	FILE *file;
539 
540 	file = popen(command, "r");
541 	if (file)
542 	{
543 		size_t bytes_left = buf_size - 1; // 1 for null terminator
544 		size_t bytes_read;
545 		while (bytes_left && (bytes_read = fread(out_buf, 1, bytes_left, file)) > 0)
546 			bytes_left -= bytes_read;
547 
548 		out_buf[buf_size - bytes_left - 1] = '\0';
549 		pclose(file);
550 
551 		return 1; // ok
552 	}
553 
554 	out_buf[0] = 0; // just in case
555 	return 0; // fail
556 }
557 
run_silent_stdout(const char * cmd)558 static int run_silent_stdout(const char *cmd)
559 {
560 	char *str;
561 	int ret;
562 
563 	str = strdup(cmd);
564 #ifdef QC_OS_WIN
565 	str = append_free(str, " >NUL");
566 #else
567 	str = append_free(str, " >/dev/null");
568 #endif
569 	ret = system(str);
570 	free(str);
571 
572 	return ret;
573 }
574 
run_silent_all(const char * cmd)575 static int run_silent_all(const char *cmd)
576 {
577 	char *str;
578 	int ret;
579 
580 	str = strdup(cmd);
581 #ifdef QC_OS_WIN
582 	str = append_free(str, " >NUL 2>&1");
583 #else
584 	str = append_free(str, " >/dev/null 2>&1");
585 #endif
586 	ret = system(str);
587 	free(str);
588 
589 	return ret;
590 }
591 
run_conflog_all(const char * cmd)592 static int run_conflog_all(const char *cmd)
593 {
594 	char *str;
595 	int ret;
596 
597 	str = strdup(cmd);
598 #ifdef QC_OS_WIN
599 	str = append_free(str, " >..\\conf.log 2>&1");
600 #else
601 	str = append_free(str, " >../conf.log 2>&1");
602 #endif
603 	if (qc_verbose)
604 		printf("Starting \"%s\"\n", str);
605 	ret = system(str);
606 	free(str);
607 
608 	return ret;
609 }
610 
qc_ensuredir(const char * path)611 static int qc_ensuredir(const char *path)
612 {
613 #ifdef QC_OS_WIN
614 	if(_mkdir(path) == 0)
615 		return 1;
616 	else if(errno == EEXIST)
617 		return 1;
618 	else
619 		return 0;
620 #else
621 	if(mkdir(path, S_IRWXU | S_IRWXG) == 0)
622 		return 1;
623 	else if(errno == EEXIST)
624 		return 1;
625 	else
626 		return 0;
627 #endif
628 }
629 
qc_chdir(const char * path)630 static int qc_chdir(const char *path)
631 {
632 	int ret;
633 
634 #ifdef QC_OS_WIN
635 	ret = _chdir(path);
636 #else
637 	ret = chdir(path);
638 #endif
639 
640 	if(ret == 0)
641 		return 1;
642 	else
643 		return 0;
644 }
645 
qc_removedir(const char * path)646 static int qc_removedir(const char *path)
647 {
648 	char *str;
649 	int ret;
650 
651 #ifdef QC_OS_WIN
652 	str = strdup("deltree /y ");
653 	str = append_free(str, path);
654 	ret = run_silent_all(str);
655 	free(str);
656 	if(ret != 0)
657 	{
658 		str = strdup("rmdir /s /q ");
659 		str = append_free(str, path);
660 		ret = run_silent_all(str);
661 		free(str);
662 	}
663 #else
664 	str = strdup("rm -rf ");
665 	str = append_free(str, path);
666 	ret = system(str);
667 	free(str);
668 #endif
669 
670 	if(ret == 0)
671 		return 1;
672 	else
673 		return 0;
674 }
675 
gen_file(qcdata_t * q,const char * name,const char * dest)676 static int gen_file(qcdata_t *q, const char *name, const char *dest)
677 {
678 	int at;
679 	char *str, *npath;
680 	FILE *fp;
681 
682 	at = find_file(q->files, q->files_count, name);
683 	if(at == -1)
684 		return 0;
685 
686 	str = strdup(dest);
687 	str = append_free(str, "/");
688 	str = append_free(str, name);
689 	npath = separators_to_native(str);
690 	free(str);
691 	fp = fopen(npath, "wb");
692 	free(npath);
693 	if(!fp)
694 		return 0;
695 	/*if(*/fwrite(q->files[at].data, q->files[at].size, 1, fp);/* < 1)
696 	{
697 		fclose(fp);
698 		return 0;
699 	}*/
700 	fclose(fp);
701 	return 1;
702 }
703 
gen_files(qcdata_t * q,const char * dest)704 static int gen_files(qcdata_t *q, const char *dest)
705 {
706 	if(!gen_file(q, "modules.cpp", dest))
707 		return 0;
708 	if(!gen_file(q, "modules_new.cpp", dest))
709 		return 0;
710 	if(!gen_file(q, "conf4.h", dest))
711 		return 0;
712 	if(!gen_file(q, "conf4.cpp", dest))
713 		return 0;
714 	if(!gen_file(q, "conf4.pro", dest))
715 		return 0;
716 	return 1;
717 }
718 
try_make(const char * makecmd,char ** maketool)719 static int try_make(const char *makecmd, char **maketool)
720 {
721 	char *str;
722 	int ret;
723 
724 	str = strdup(makecmd);
725 	str = append_free(str, " clean");
726 	ret = run_conflog_all(str);
727 	free(str);
728 	if(ret != 0)
729 		return 0;
730 
731 	if(run_conflog_all(makecmd) != 0) {
732 		if (qc_verbose)
733 			printf("\"%s\" failed\n", makecmd);
734 		return 0;
735 	}
736 
737 	*maketool = strdup(makecmd);
738 	return 1;
739 }
740 
741 static char *maketool_list_common[] =
742 {
743 	"mingw32-make",
744 	"make",
745 	"jom",
746 	"nmake",
747 	NULL
748 };
749 
750 static char *maketool_list_mingw[] =
751 {
752 	"make",
753 	"mingw32-make",
754 	NULL
755 };
756 
757 static char *maketool_list_vs[] =
758 {
759 	"jom",
760 	"nmake",
761 	NULL
762 };
763 
do_conf_create(qcdata_t * q,const char * qmake_path,const char * spec,char ** maketool)764 static int do_conf_create(qcdata_t *q, const char *qmake_path, const char *spec, char **maketool)
765 {
766 	char *str;
767 	int n;
768 	int at;
769 	char **maketool_list;
770 
771 	if(!qc_ensuredir(qconftemp_path))
772 		return 0;
773 
774 	if(!gen_files(q, qconftemp_path))
775 		return 0;
776 
777 	if(!qc_chdir(qconftemp_path))
778 		return 0;
779 
780 	// TODO: support -spec once QC_MAKESPEC matters
781 	str = strdup(qmake_path);
782 	str = append_free(str, " conf4.pro");
783 	if(run_silent_stdout(str) != 0)
784 	{
785 		free(str);
786 		qc_chdir("..");
787 		return 0;
788 	}
789 	free(str);
790 
791 	at = -1;
792 	if (strstr(spec, "win32-msvc")) {
793 		maketool_list = maketool_list_vs;
794 	} else if(strstr(spec, "win32-g++")) {
795 		maketool_list = maketool_list_mingw;
796 	} else {
797 		maketool_list = maketool_list_common;
798 	}
799 	for(n = 0; maketool_list[n]; ++n)
800 	{
801 		if(qc_verbose)
802 			printf("Trying \"%s\"\n", maketool_list[n]);
803 		if(try_make(maketool_list[n], maketool))
804 		{
805 			at = n;
806 			break;
807 		}
808 	}
809 
810 	qc_chdir("..");
811 	if(at == -1)
812 		return 0;
813 
814 	return 1;
815 }
816 
do_conf_run()817 static int do_conf_run()
818 {
819 	char *str, *npath;
820 	int ret;
821 
822 	str = strdup(qconftemp_path);
823 	str = append_free(str, "/conf");
824 	npath = separators_to_native(str);
825 	free(str);
826 	ret = system(npath);
827 	free(npath);
828 
829 	return ret;
830 }
831 
cleanup_qconftemp()832 static void cleanup_qconftemp()
833 {
834 	qc_removedir(qconftemp_path);
835 }
836 
try_print_var(const char * var,const char * val)837 static void try_print_var(const char *var, const char *val)
838 {
839 	printf("%s=", var);
840 	if(val)
841 		printf("%s", val);
842 	printf("\n");
843 }
844 
do_conf(qcdata_t * q,const char * argv0)845 static int do_conf(qcdata_t *q, const char *argv0)
846 {
847 	char *qmake_path;
848 	char *maketool;
849 	int qt_maj_version = 0;
850 	char *specs_name = NULL;
851 	int n;
852 	int ret;
853 
854 	printf("Configuring %s ...\n", q->pro_name);
855 
856 	if(qc_verbose)
857 	{
858 		printf("\n");
859 		for(n = 0; n < q->args_count; ++n)
860 			try_print_var(q->args[n].envvar, q->args[n].val);
861 	}
862 
863 	printf("Verifying Qt build environment ... ");
864 	fflush(stdout);
865 
866 	if(qc_verbose)
867 		printf("\n");
868 
869 	qmake_path = find_qmake();
870 	if(!qmake_path)
871 	{
872 		if(qc_verbose)
873 			printf(" -> fail\n");
874 		else
875 			printf("fail\n");
876 		printf("\n");
877 		printf("Reason: Unable to find the 'qmake' tool for Qt %s.\n", qtsearchtext);
878 		printf("\n");
879 		printf("%s", q->qtinfo);
880 		return 0;
881 	}
882 	if(qc_verbose)
883 		printf("qmake found in %s\n", qmake_path);
884 
885 	// figure out what version it is.
886 	{
887 		char buf[20]; // version string output always small
888 		if (qmake_query_maj_ver(qmake_path, buf, sizeof(buf))) {
889 			qt_maj_version = strtoul(buf, NULL, 10);
890 			if (qt_maj_version == ULONG_MAX)
891 				qt_maj_version = 0;
892 		}
893 		if (qt_maj_version == 0) {
894 			if(qc_verbose) {
895 				printf(" -> fail\n");
896 				printf("Qt major version is not parsable\n");
897 			} else
898 				printf("fail\n");
899 			free(qmake_path);
900 			return 0;
901 		}
902 	}
903 
904 	// find specc name
905 	{
906 		char *spec = get_envvar("QMAKESPEC");
907 		if (!spec) {
908 			// try to find default spec
909 			if (qt_maj_version > 4) {
910 				char buf[32];
911 				if (qmake_query(qmake_path, "QMAKE_XSPEC", buf, sizeof(buf))) // or QMAKE_SPEC ?
912 					specs_name = strdup(buf);
913 				// it's possible to compute full path like QT_HOST_DATA/QMAKE_XSPEC
914 			} else {
915 				char *qmake_conf, buf[1024];
916 				FILE *fp;
917 				qmake_query(qmake_path, "QMAKE_MKSPECS", buf, sizeof(buf));
918 				qmake_conf = append_free(strdup(buf), "/default/qmake.conf");
919 				fp = fopen(qmake_conf, "r");
920 				free(qmake_conf);
921 				if (fp) {
922 					size_t br;
923 					if ((br = fread(buf, 1, sizeof(buf) - 1, fp)) > 0) {
924 						char *str, *end;
925 						buf[br] = 0;
926 						str = strstr(buf, "QMAKESPEC_ORIGINAL=");
927 						if (str) {
928 							str = extract_spec_name(str);
929 							if (str) {
930 								specs_name = strdup(str);
931 							}
932 						}
933 					}
934 					fclose(fp);
935 				}
936 			}
937 		} else {
938 			char *s = strdup(spec);
939 			specs_name = extract_spec_name(s);
940 			if (specs_name) {
941 				specs_name = strdup(specs_name);
942 			}
943 			free(s);
944 		}
945 	}
946 
947 	// TODO: in verbose mode, print out default makespec and what we're
948 	//   overriding the makespec to (if any).  since at this time we don't
949 	//   ever override the makespec on windows, we don't need this yet.
950 
951 	cleanup_qconftemp();
952 	maketool = NULL;
953 	if(!do_conf_create(q, qmake_path, specs_name, &maketool))
954 	{
955 		cleanup_qconftemp();
956 		if(qc_verbose)
957 			printf(" -> fail\n");
958 		else
959 			printf("fail\n");
960 		printf("\n");
961 		printf("Reason: There was an error compiling 'conf'.  See conf.log for details.\n");
962 		printf("\n");
963 		printf("%s", q->qtinfo);
964 
965 		if(qc_verbose)
966 		{
967 			printf("conf.log:\n");
968 			system("type conf.log");
969 		}
970 
971 		free(qmake_path);
972 		return 0;
973 	}
974 
975 	set_envvar("QC_COMMAND", argv0);
976 	set_envvar("QC_PROFILE", q->pro_file);
977 	set_envvar("QC_QMAKE", qmake_path);
978 	// TODO: unix configure will set QC_MAKESPEC here if it needs to
979 	//   override the mkspec.  currently, it only does this for macx-xcode
980 	//   so the behavior doesn't apply to windows yet.
981 	set_envvar("QC_MAKETOOL", maketool);
982 
983 	free(qmake_path);
984 
985 	ret = do_conf_run();
986 	if(ret == 1)
987 	{
988 		cleanup_qconftemp();
989 		printf("\n");
990 		free(maketool);
991 		return 0;
992 	}
993 	else if(ret != 0)
994 	{
995 		cleanup_qconftemp();
996 		if(qc_verbose)
997 			printf(" -> fail\n");
998 		else
999 			printf("fail\n");
1000 		printf("\n");
1001 		printf("Reason: Unexpected error launching 'conf'\n");
1002 		printf("\n");
1003 		free(maketool);
1004 		return 0;
1005 	}
1006 
1007 	cleanup_qconftemp();
1008 	printf("\n");
1009 	printf("Good, your configure finished.  Now run %s.\n", maketool);
1010 	printf("\n");
1011 	free(maketool);
1012 
1013 	return 1;
1014 }
1015 
main(int argc,char ** argv)1016 int main(int argc, char **argv)
1017 {
1018 	unsigned char *data;
1019 	unsigned int size;
1020 	qcdata_t *q;
1021 	int n;
1022 	int at;
1023 	int quit;
1024 	char *arg, *var, *val;
1025 
1026 	if(!embed_get_data(argv[0], &data, &size))
1027 	{
1028 		fprintf(stderr, "Error: Can't import data.\n");
1029 		return 1;
1030 	}
1031 
1032 	q = parse_data(data, size);
1033 	if(!q)
1034 	{
1035 		fprintf(stderr, "Error: Can't parse internal data.\n");
1036 		free(data);
1037 		return 1;
1038 	}
1039 
1040 	if(q->usage)
1041 	{
1042 		val = find_replace(q->usage, "$0", argv[0]);
1043 		free(q->usage);
1044 		q->usage = val;
1045 	}
1046 
1047 	quit = 0;
1048 	for(n = 1; n < argc && !quit; ++n)
1049 	{
1050 		arg = argv[n];
1051 
1052 		if(arg[0] != '-' || arg[1] != '-')
1053 		{
1054 			printf("%s", q->usage);
1055 			quit = 1;
1056 			break;
1057 		}
1058 
1059 		at = index_of(arg + 2, '=');
1060 		if(at != -1)
1061 		{
1062 			var = alloc_str((unsigned char *)arg + 2, at);
1063 			val = strdup(arg + 2 + at + 1);
1064 		}
1065 		else
1066 		{
1067 			var = strdup(arg + 2);
1068 			val = 0;
1069 		}
1070 
1071 		if(strcmp(var, "help") == 0)
1072 		{
1073 			printf("%s", q->usage);
1074 			quit = 1;
1075 		}
1076 		else if(strcmp(var, "verbose") == 0)
1077 		{
1078 			qc_verbose = 1;
1079 			set_envvar("QC_VERBOSE", "Y");
1080 		}
1081 		else if(strcmp(var, "prefix") == 0)
1082 		{
1083 			prefix = strdup(val);
1084 		}
1085 		else if(strcmp(var, "bindir") == 0)
1086 		{
1087 			bindir = strdup(val);
1088 		}
1089 		else if(strcmp(var, "includedir") == 0)
1090 		{
1091 			includedir = strdup(val);
1092 		}
1093 		else if(strcmp(var, "datadir") == 0)
1094 		{
1095 			datadir = strdup(val);
1096 		}
1097 		else if(strcmp(var, "libdir") == 0)
1098 		{
1099 			libdir = strdup(val);
1100 		}
1101 		else if(strcmp(var, "qtselect") == 0)
1102 		{
1103 			if (val && strlen(val))
1104 				qc_qtselect = parse_qtselect(val);
1105 		}
1106 		else
1107 		{
1108 			at = find_arg(q->args, q->args_count, var);
1109 			if(at != -1)
1110 			{
1111 				// keep a stash of ex_qtdir
1112 				if(strcmp(var, "qtdir") == 0)
1113 				{
1114 					if(ex_qtdir)
1115 						free(ex_qtdir);
1116 					ex_qtdir = strdup(val);
1117 				}
1118 
1119 				if(q->args[at].val)
1120 					free(q->args[at].val);
1121 
1122 				if(q->args[at].type == ArgValue)
1123 					q->args[at].val = strdup(val);
1124 				else // ArgFlag
1125 					q->args[at].val = strdup("Y");
1126 
1127 				set_envvar(q->args[at].envvar, q->args[at].val);
1128 			}
1129 			else
1130 			{
1131 				printf("%s", q->usage);
1132 				quit = 1;
1133 			}
1134 		}
1135 
1136 		free(var);
1137 		if(val)
1138 			free(val);
1139 	}
1140 
1141 	if(quit)
1142 	{
1143 		qcdata_delete(q);
1144 		if(ex_qtdir)
1145 			free(ex_qtdir);
1146 
1147 		if(qc_qtselect)
1148 			free(qc_qtselect);
1149 
1150 		if(prefix)
1151 			free(prefix);
1152 
1153 		if(bindir)
1154 			free(bindir);
1155 
1156 		if(includedir)
1157 			free(includedir);
1158 
1159 		if(libdir)
1160 			free(libdir);
1161 
1162 		if(datadir)
1163 			free(datadir);
1164 
1165 		return 1;
1166 	}
1167 
1168 	if(prefix)
1169 	{
1170 		set_envvar("PREFIX", prefix);
1171 		if(!libdir)
1172 			libdir = append_str(prefix, "/lib");
1173 
1174 		if(!bindir)
1175 			bindir = append_str(prefix, "/bin");
1176 
1177 		if(!includedir)
1178 			includedir = append_str(prefix, "/include");
1179 
1180 		if(!datadir)
1181 			datadir = append_str(prefix, "/share");
1182 	}
1183 
1184 	if(libdir)
1185 		set_envvar("LIBDIR", libdir);
1186 
1187 	if(bindir)
1188 		set_envvar("BINDIR", bindir);
1189 
1190 	if(includedir)
1191 		set_envvar("INCLUDEDIR", includedir);
1192 
1193 	if(datadir)
1194 		set_envvar("DATADIR", datadir);
1195 
1196 	if(libdir)
1197 		set_envvar("LIBDIR", libdir);
1198 
1199 	n = do_conf(q, argv[0]);
1200 	qcdata_delete(q);
1201 	if(ex_qtdir)
1202 		free(ex_qtdir);
1203 
1204 	if(qc_qtselect)
1205 		free(qc_qtselect);
1206 
1207 	if(prefix)
1208 		free(prefix);
1209 
1210 	if(bindir)
1211 		free(bindir);
1212 
1213 	if(includedir)
1214 		free(includedir);
1215 
1216 	if(libdir)
1217 		free(libdir);
1218 
1219 	if(datadir)
1220 		free(datadir);
1221 
1222 	if(n)
1223 		return 0;
1224 	else
1225 		return 1;
1226 }
1227