Subversion Repositories Tewi

Rev

Rev 257 | Rev 299 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 nishi 1
/* $Id: main.c 284 2024-10-09 02:44:20Z nishi $ */
2
 
16 nishi 3
#define SOURCE
4
 
43 nishi 5
#include "../config.h"
6
 
215 nishi 7
#ifdef __BORLANDC__
8
 
244 nishi 9
#pragma resource "gui_bcc.res"
215 nishi 10
 
11
#endif
12
 
13
#if !defined(_MSC_VER) && !defined(__BORLANDC__)
189 nishi 14
#include <unistd.h>
212 nishi 15
#endif
3 nishi 16
#include <stdio.h>
17
#include <stdbool.h>
18
#include <string.h>
16 nishi 19
#include <signal.h>
116 nishi 20
#include <stdlib.h>
3 nishi 21
 
43 nishi 22
#ifndef NO_SSL
6 nishi 23
#include <openssl/opensslv.h>
43 nishi 24
#endif
6 nishi 25
 
3 nishi 26
#include <cm_log.h>
62 nishi 27
#include <cm_string.h>
3 nishi 28
 
4 nishi 29
#include "tw_config.h"
8 nishi 30
#include "tw_server.h"
3 nishi 31
#include "tw_version.h"
32
 
244 nishi 33
#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
51 nishi 34
#include <windows.h>
35
#endif
36
 
182 nishi 37
#ifdef _PSP
38
#include <pspkernel.h>
39
#include <pspdebug.h>
183 nishi 40
#include <pspsdk.h>
41
#include <psputility.h>
42
#include <pspctrl.h>
43
#include <pspnet_apctl.h>
44
#include <pspwlan.h>
182 nishi 45
 
46
PSP_MODULE_INFO("Tewi HTTPd", PSP_MODULE_USER, 1, 1);
47
PSP_MAIN_THREAD_ATTR(PSP_THREAD_ATTR_USER);
48
 
49
#define printf(...) pspDebugScreenPrintf(__VA_ARGS__)
183 nishi 50
#define STDERR_LOG(...) pspDebugScreenPrintf(__VA_ARGS__)
189 nishi 51
#elif defined(__ps2sdk__)
52
#include <debug.h>
200 nishi 53
#include <iopcontrol.h>
189 nishi 54
#include <sifrpc.h>
200 nishi 55
#include <kernel.h>
189 nishi 56
 
57
#define printf(...) scr_printf(__VA_ARGS__)
58
#define STDERR_LOG(...) scr_printf(__VA_ARGS__)
191 nishi 59
#elif defined(__PPU__)
60
#include <rsx/gcm_sys.h>
61
#include <rsx/rsx.h>
62
#include <sysutil/video.h>
63
#include <malloc.h>
64
#include <sys/thread.h>
65
#include <stdarg.h>
197 nishi 66
#include <png.h>
191 nishi 67
 
68
#define printf(...) tt_printf(__VA_ARGS__)
69
#define STDERR_LOG(...) tt_printf(__VA_ARGS__)
215 nishi 70
#elif defined(_MSC_VER) || defined(__BORLANDC__)
213 nishi 71
void STDERR_LOG(const char* format, ...) {
212 nishi 72
	va_list args;
73
	va_start(args, format);
74
	vfprintf(stderr, format, args);
75
	va_end(args);
76
}
183 nishi 77
#else
78
#define STDERR_LOG(...) fprintf(stderr, __VA_ARGS__)
182 nishi 79
#endif
80
 
3 nishi 81
extern bool cm_do_log;
18 nishi 82
extern struct tw_config config;
62 nishi 83
extern FILE* logfile;
3 nishi 84
 
18 nishi 85
char tw_server[2048];
86
 
62 nishi 87
int startup(int argc, char** argv);
88
 
257 nishi 89
#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__)
206 nishi 90
char* get_registry(const char* main, const char* sub) {
208 nishi 91
	DWORD bufsize = 512;
92
	HKEY handle;
93
	char* value = malloc(513);
94
	int err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, main, 0, KEY_QUERY_VALUE, &handle);
206 nishi 95
	if(err == ERROR_SUCCESS) {
208 nishi 96
		err = RegQueryValueEx(handle, sub, NULL, NULL, value, &bufsize);
97
		if(err != ERROR_SUCCESS) {
98
			free(value);
99
			RegCloseKey(handle);
100
			return NULL;
101
		}
102
		RegCloseKey(handle);
206 nishi 103
		return value;
104
	} else {
105
		free(value);
106
		return NULL;
107
	}
108
}
109
#endif
110
 
62 nishi 111
#ifdef SERVICE
112
SERVICE_STATUS status;
113
SERVICE_STATUS_HANDLE status_handle;
114
 
70 nishi 115
void WINAPI servhandler(DWORD control) {
116
	switch(control) {
117
	case SERVICE_CONTROL_STOP:
118
	case SERVICE_CONTROL_SHUTDOWN:
119
		status.dwCurrentState = SERVICE_STOP_PENDING;
120
		break;
62 nishi 121
	}
122
	SetServiceStatus(status_handle, &status);
123
}
124
 
70 nishi 125
void WINAPI servmain(DWORD argc, LPSTR* argv) {
206 nishi 126
	char* path = get_registry("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Tewi HTTPd", "InstallDir");
284 nishi 127
	int st;
206 nishi 128
	if(path != NULL) {
129
		char* lpath = cm_strcat(path, "/logs/tewi.log");
130
		logfile = fopen(lpath, "a");
131
		free(lpath);
132
		free(path);
133
	} else {
134
		logfile = fopen(PREFIX "/logs/tewi.log", "a");
135
	}
62 nishi 136
	if(logfile == NULL) logfile = stderr;
137
	status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
138
	status.dwCurrentState = SERVICE_START_PENDING;
139
	status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
140
	status.dwWin32ExitCode = NO_ERROR;
141
	status.dwServiceSpecificExitCode = 0;
142
	status.dwCheckPoint = 0;
143
	status.dwWaitHint = 0;
144
	status_handle = RegisterServiceCtrlHandler("Tewi HTTPd", servhandler);
145
	if(status_handle == NULL) return;
146
	if(SetServiceStatus(status_handle, &status) == 0) return;
284 nishi 147
	st = startup(argc, argv);
70 nishi 148
	if(st != -1) {
62 nishi 149
		status.dwWin32ExitCode = NO_ERROR;
150
		status.dwServiceSpecificExitCode = st;
151
		status.dwCurrentState = SERVICE_STOPPED;
152
		SetServiceStatus(status_handle, &status);
153
		return;
154
	}
155
	status.dwCurrentState = SERVICE_RUNNING;
156
	SetServiceStatus(status_handle, &status);
157
	tw_server_loop();
158
	status.dwCurrentState = SERVICE_STOPPED;
159
	SetServiceStatus(status_handle, &status);
160
}
161
#endif
162
 
183 nishi 163
int running = 1;
164
#ifdef _PSP
165
 
166
int psp_exit_callback(int arg1, int arg2, void* arg3) { running = 0; }
167
 
168
int psp_callback_thread(SceSize args, void* argp) {
169
	int cid;
170
	cid = sceKernelCreateCallback("Exit Call Back", psp_exit_callback, NULL);
171
	sceKernelRegisterExitCallback(cid);
172
	sceKernelSleepThreadCB();
173
	return 0;
174
}
175
#endif
176
 
191 nishi 177
#ifdef __PPU__
178
uint32_t depth_pitch;
179
uint32_t depth_offset;
180
uint32_t* depth_buffer;
181
 
182
#define CB_SIZE 0x100000
183
#define HOST_SIZE (32 * 1024 * 1024)
184
 
185
struct rsx_buffer {
186
	int width, height, id;
187
	uint32_t* ptr;
188
	uint32_t offset;
189
};
190
 
191
void wait_rsx(gcmContextData* ctx, uint32_t label) {
192
	rsxSetWriteBackendLabel(ctx, GCM_INDEX_TYPE_32B, label);
193
 
194
	rsxFlushBuffer(ctx);
195
 
196
	while(*(uint32_t*)gcmGetLabelAddress(GCM_INDEX_TYPE_32B) != label) usleep(50);
197
 
198
	label++;
199
}
200
 
201
void wait_rsx_until_idle(gcmContextData* ctx) {
202
	uint32_t label = 1;
203
	rsxSetWriteBackendLabel(ctx, GCM_INDEX_TYPE_32B, label);
204
	rsxSetWaitLabel(ctx, GCM_INDEX_TYPE_32B, label);
205
	label++;
206
	wait_rsx(ctx, label);
207
}
208
 
209
void get_resolution(int* width, int* height) {
210
	videoState state;
211
	videoResolution res;
212
	if(videoGetState(0, 0, &state) != 0) {
213
		return;
214
	}
215
 
216
	if(state.state != 0) {
217
		return;
218
	}
219
 
220
	if(videoGetResolution(state.displayMode.resolution, &res) != 0) {
221
		return;
222
	}
223
	*width = res.width;
224
	*height = res.height;
225
}
226
 
227
void make_buffer(struct rsx_buffer* buffer, int id) {
228
	int w, h;
229
	get_resolution(&w, &h);
230
 
231
	buffer->ptr = (uint32_t*)rsxMemalign(64, 4 * w * h);
232
	if(buffer->ptr == NULL) return;
233
 
234
	if(rsxAddressToOffset(buffer->ptr, &buffer->offset) != 0) return;
235
 
236
	if(gcmSetDisplayBuffer(id, buffer->offset, 4 * w, w, h) != 0) return;
237
	buffer->width = w;
238
	buffer->height = h;
239
	buffer->id = id;
240
}
241
 
242
gcmContextData* init_screen(void) {
243
	void* host = memalign(1024 * 1024, HOST_SIZE);
244
	gcmContextData* ctx = NULL;
245
	videoState state;
246
	videoConfiguration vconfig;
247
	videoResolution res;
248
	rsxInit(&ctx, CB_SIZE, HOST_SIZE, host);
249
	if(ctx == NULL) {
250
		free(host);
251
		return NULL;
252
	}
253
 
254
	if(videoGetState(0, 0, &state) != 0) {
255
		rsxFinish(ctx, 0);
256
		free(host);
257
		return NULL;
258
	}
259
 
260
	if(state.state != 0) {
261
		rsxFinish(ctx, 0);
262
		free(host);
263
		return NULL;
264
	}
265
 
266
	if(videoGetResolution(state.displayMode.resolution, &res) != 0) {
267
		rsxFinish(ctx, 0);
268
		free(host);
269
		return NULL;
270
	}
271
 
272
	memset(&vconfig, 0, sizeof(vconfig));
273
	vconfig.resolution = state.displayMode.resolution;
274
	vconfig.format = VIDEO_BUFFER_FORMAT_XRGB;
275
	vconfig.pitch = res.width * 4;
276
	vconfig.aspect = state.displayMode.aspect;
277
 
278
	wait_rsx_until_idle(ctx);
279
 
280
	if(videoConfigure(0, &vconfig, NULL, 0) != 0) {
281
		rsxFinish(ctx, 0);
282
		free(host);
283
		return NULL;
284
	}
285
 
286
	if(videoGetState(0, 0, &state) != 0) {
287
		rsxFinish(ctx, 0);
288
		free(host);
289
		return NULL;
290
	}
291
	gcmSetFlipMode(GCM_FLIP_VSYNC);
292
 
293
	depth_pitch = res.width * 4;
294
	depth_buffer = (uint32_t*)rsxMemalign(64, (res.height * depth_pitch) * 2);
295
	rsxAddressToOffset(depth_buffer, &depth_offset);
296
 
297
	gcmResetFlipStatus();
298
 
299
	return ctx;
300
}
301
 
302
void set_render_target(gcmContextData* context, struct rsx_buffer* buffer) {
303
	gcmSurface sf;
304
 
305
	sf.colorFormat = GCM_SURFACE_X8R8G8B8;
306
	sf.colorTarget = GCM_SURFACE_TARGET_0;
307
	sf.colorLocation[0] = GCM_LOCATION_RSX;
308
	sf.colorOffset[0] = buffer->offset;
309
	sf.colorPitch[0] = depth_pitch;
310
 
311
	sf.colorLocation[1] = GCM_LOCATION_RSX;
312
	sf.colorLocation[2] = GCM_LOCATION_RSX;
313
	sf.colorLocation[3] = GCM_LOCATION_RSX;
314
	sf.colorOffset[1] = 0;
315
	sf.colorOffset[2] = 0;
316
	sf.colorOffset[3] = 0;
317
	sf.colorPitch[1] = 64;
318
	sf.colorPitch[2] = 64;
319
	sf.colorPitch[3] = 64;
320
 
321
	sf.depthFormat = GCM_SURFACE_ZETA_Z16;
322
	sf.depthLocation = GCM_LOCATION_RSX;
323
	sf.depthOffset = depth_offset;
324
	sf.depthPitch = depth_pitch;
325
 
326
	sf.type = GCM_TEXTURE_LINEAR;
327
	sf.antiAlias = GCM_SURFACE_CENTER_1;
328
 
329
	sf.width = buffer->width;
330
	sf.height = buffer->height;
331
	sf.x = 0;
332
	sf.y = 0;
333
 
334
	rsxSetSurface(context, &sf);
335
}
336
 
337
void wait_flip(void) {
338
	while(gcmGetFlipStatus() != 0) usleep(200);
339
	gcmResetFlipStatus();
340
}
341
 
342
void flip(gcmContextData* ctx, uint32_t buffer) {
343
	if(gcmSetFlip(ctx, buffer) == 0) {
344
		rsxFlushBuffer(ctx);
345
		gcmSetWaitFlip(ctx);
346
	}
347
}
348
 
349
uint8_t* tvram;
350
 
351
extern uint8_t font[];
352
 
353
int tt_x = 0;
354
int tt_y = 0;
355
int tt_width;
356
int tt_height;
357
 
358
void tt_putstr(const char* str) {
359
	int i;
193 nishi 360
	for(i = 0; str[i] != 0; i++) {
191 nishi 361
		tvram[tt_y * tt_width + tt_x] = str[i];
193 nishi 362
		if(str[i] == '\n') {
191 nishi 363
			tt_x = 0;
364
			tt_y++;
193 nishi 365
		} else {
191 nishi 366
			tt_x++;
193 nishi 367
			if(tt_x == tt_width) {
191 nishi 368
				tt_x = 0;
369
				tt_y++;
370
			}
371
		}
193 nishi 372
		if(tt_y == tt_height) {
191 nishi 373
			tt_y--;
374
			int x, y;
193 nishi 375
			for(y = 0; y < tt_height - 1; y++) {
376
				for(x = 0; x < tt_width; x++) {
191 nishi 377
					tvram[y * tt_width + x] = tvram[(y + 1) * tt_width + x];
378
				}
379
			}
193 nishi 380
			for(x = 0; x < tt_width; x++) {
197 nishi 381
				tvram[(tt_height - 1) * tt_width + x] = 0x20;
191 nishi 382
			}
383
		}
384
	}
385
}
386
 
193 nishi 387
void tt_putchar(struct rsx_buffer* buffer, int x, int y, uint8_t c) {
191 nishi 388
	int i, j;
197 nishi 389
	if(c == 0) return;
191 nishi 390
	if(c < 0x20) c = 0x20;
391
	if(c >= 0x7f) c = 0x20;
197 nishi 392
	for(i = 0; i < 8; i++) {
393
		uint8_t l = i == 7 ? 0 : font[(c - 0x20) * 8 + i];
394
		for(j = 0; j < 6; j++) {
395
			uint32_t col = 0;
193 nishi 396
			if(l & (1 << 7)) {
197 nishi 397
				col = 0xffffff;
191 nishi 398
			}
399
			l = l << 1;
197 nishi 400
			buffer->ptr[(y * 8 + i) * buffer->width + x * 6 + j] = col;
191 nishi 401
		}
402
	}
403
}
404
 
405
void draw(struct rsx_buffer* buffer, int current) {
406
	int i, j, c;
407
	for(i = 0; i < buffer->height / 8; i++) {
408
		for(j = 0; j < buffer->width / 6; j++) {
409
			uint8_t c = tvram[i * (buffer->width / 6) + j];
410
			tt_putchar(buffer, j, i, c);
411
		}
412
	}
413
}
414
 
197 nishi 415
#define BUFFERS 1
191 nishi 416
gcmContextData* ctx;
417
struct rsx_buffer buffers[BUFFERS];
418
 
419
void text_thread(void* arg) {
420
	int current = 0;
421
	while(1) {
422
		wait_flip();
423
		draw(&buffers[current], current);
424
		flip(ctx, buffers[current].id);
425
		current++;
426
		if(current >= BUFFERS) current = 0;
427
	}
428
}
429
 
430
void tt_printf(const char* tmpl, ...) {
431
	va_list va;
432
	va_start(va, tmpl);
433
	int i;
434
	char cbuf[2];
435
	cbuf[1] = 0;
436
	char* log = cm_strdup("");
437
	for(i = 0; tmpl[i] != 0; i++) {
438
		if(tmpl[i] == '%') {
439
			i++;
193 nishi 440
			if(tmpl[i] == 's') {
191 nishi 441
				char* tmp = log;
442
				log = cm_strcat(tmp, va_arg(va, char*));
443
				free(tmp);
193 nishi 444
			} else if(tmpl[i] == 'd') {
191 nishi 445
				char buf[513];
446
				sprintf(buf, "%d", va_arg(va, int));
447
				char* tmp = log;
448
				log = cm_strcat(tmp, buf);
449
				free(tmp);
193 nishi 450
			} else if(tmpl[i] == '%') {
191 nishi 451
				char* tmp = log;
452
				log = cm_strcat(tmp, "%");
453
				free(tmp);
454
			}
455
		} else {
456
			cbuf[0] = tmpl[i];
457
			char* tmp = log;
458
			log = cm_strcat(tmp, cbuf);
459
			free(tmp);
460
		}
461
	}
462
	va_end(va);
463
	tt_putstr(log);
464
}
465
 
197 nishi 466
void show_png(void) {
467
	FILE* f = fopen(PREFIX "/pbtewi.png", "rb");
468
	if(f == NULL) {
469
		f = fopen(PREFIX "/../ICON0.PNG", "rb");
470
	}
471
	if(f == NULL) return;
472
	png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
473
	png_infop info = png_create_info_struct(png);
474
	if(setjmp(png_jmpbuf(png))) {
475
		png_destroy_read_struct(&png, &info, NULL);
476
		fclose(f);
477
		return;
478
	}
479
 
480
	png_init_io(png, f);
481
	png_read_info(png, info);
482
 
483
	int width = png_get_image_width(png, info);
484
	int height = png_get_image_height(png, info);
485
	int depth = png_get_bit_depth(png, info);
486
	int type = png_get_color_type(png, info);
487
 
488
	if(depth == 16) png_set_strip_16(png);
489
	if(type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
490
	if(type == PNG_COLOR_TYPE_GRAY && depth < 8) png_set_expand_gray_1_2_4_to_8(png);
491
	if(png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png);
492
	if(type == PNG_COLOR_TYPE_RGB || type == PNG_COLOR_TYPE_GRAY || type == PNG_COLOR_TYPE_PALETTE) png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
493
	if(type == PNG_COLOR_TYPE_GRAY || type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png);
494
	png_read_update_info(png, info);
495
	png_bytep* rows = (png_bytep*)malloc(sizeof(*rows) * (height));
496
 
497
	int i;
498
 
499
	for(i = 0; i < height; i++) {
500
		rows[i] = (png_byte*)malloc(png_get_rowbytes(png, info));
501
	}
502
 
503
	png_read_image(png, rows);
504
 
505
	for(i = 0; i < height; i++) {
506
		int j;
507
		for(j = 0; j < width; j++) {
508
			png_bytep byte = &(rows[i][j * 4]);
509
			uint32_t col = (byte[0] << 16) | (byte[1] << 8) | (byte[2]);
510
			int k;
511
			for(k = 0; k < BUFFERS; k++) {
512
				buffers[k].ptr[buffers[k].width * i - width + j] = col;
513
			}
514
		}
515
	}
516
 
517
	png_destroy_read_struct(&png, &info, NULL);
518
	fclose(f);
519
 
520
	for(i = 0; i < height; i++) {
521
		free(rows[i]);
522
	}
523
	free(rows);
524
}
525
 
191 nishi 526
#endif
527
 
253 nishi 528
#if !defined(BUILD_GUI_VALID)
3 nishi 529
int main(int argc, char** argv) {
212 nishi 530
	int st;
62 nishi 531
#ifdef SERVICE
532
	SERVICE_TABLE_ENTRY table[] = {{"Tewi HTTPd", servmain}, {NULL, NULL}};
284 nishi 533
	logfile = stderr;
534
	if(!StartServiceCtrlDispatcher(table)){
535
		printf("Failed to start the service dispatcher\n");
536
		return 1;
537
	}
62 nishi 538
#else
284 nishi 539
	logfile = stderr;
182 nishi 540
#ifdef _PSP
541
	pspDebugScreenInit();
542
	pspDebugScreenSetXY(0, 0);
183 nishi 543
	printf("PSP Bootstrap, Tewi/%s\n", tw_get_version());
544
	int thid = sceKernelCreateThread("update_thread", psp_callback_thread, 0x11, 0xfa0, 0, NULL);
545
	if(thid >= 0) {
546
		sceKernelStartThread(thid, 0, NULL);
547
	} else {
548
		printf("Failed to start thread\n");
549
		while(running) sceKernelDelayThread(50 * 1000);
550
		sceKernelExitGame();
551
	}
552
	sceCtrlSetSamplingCycle(0);
553
	sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
554
	sceUtilityLoadNetModule(PSP_NET_MODULE_COMMON);
555
	sceUtilityLoadNetModule(PSP_NET_MODULE_INET);
556
	if(pspSdkInetInit()) {
557
		printf("Could not init the network\n");
558
		while(running) sceKernelDelayThread(50 * 1000);
559
		sceKernelExitGame();
560
	} else {
561
		printf("Network initialization successful\n");
562
	}
563
	if(sceWlanGetSwitchState() != 1) {
564
		printf("Turn the Wi-Fi switch on\n");
565
		while(sceWlanGetSwitchState() != 1) {
566
			sceKernelDelayThread(1000 * 1000);
567
		}
568
	} else {
569
		printf("Wi-Fi is turned on\n");
570
	}
571
	int i;
572
	int choice[100];
573
	int incr = 0;
574
	int last = 0;
575
	int cur = 0;
576
	for(i = 1; i < 100; i++) {
577
		choice[i - 1] = 0;
578
		netData name;
579
		netData data;
580
		if(sceUtilityCheckNetParam(i) != 0) continue;
581
		choice[incr++] = i;
582
		pspDebugScreenSetXY(0, 1 + 3 + incr - 1);
583
		if(incr == 1) printf("> ");
584
		pspDebugScreenSetXY(2, 1 + 3 + incr - 1);
585
		sceUtilityGetNetParam(i, 0, &name);
586
		sceUtilityGetNetParam(i, 1, &data);
587
		printf("SSID=%s", data.asString);
588
		sceUtilityGetNetParam(i, 4, &data);
589
		if(data.asString[0]) {
590
			sceUtilityGetNetParam(i, 5, &data);
591
			printf(" IPADDR=%s\n", data.asString);
592
		} else {
593
			printf(" DHCP\n");
594
		}
595
	}
596
	int press = 0;
597
	while(1) {
598
		if(!running) {
599
			sceKernelExitGame();
600
		}
601
		SceCtrlData c;
602
		sceCtrlReadBufferPositive(&c, 1);
603
		press = 0;
604
		if(c.Buttons & PSP_CTRL_DOWN) {
605
			if(cur < incr - 1) {
606
				cur++;
607
			}
608
			press = 1;
609
		} else if(c.Buttons & PSP_CTRL_UP) {
610
			if(cur > 0) {
611
				cur--;
612
			}
613
			press = -1;
614
		} else if(c.Buttons & PSP_CTRL_START) {
615
			break;
616
		}
617
		if(last != cur) {
618
			pspDebugScreenSetXY(0, 1 + 3 + last);
619
			printf("  ");
620
			pspDebugScreenSetXY(0, 1 + 3 + cur);
621
			printf("> ");
622
			last = cur;
623
		}
624
		if(press != 0) {
625
			while(1) {
626
				SceCtrlData c;
627
				sceCtrlReadBufferPositive(&c, 1);
628
				if(press == 1) {
629
					if(!(c.Buttons & PSP_CTRL_DOWN)) break;
630
				} else if(press == -1) {
631
					if(!(c.Buttons & PSP_CTRL_UP)) break;
632
				}
633
			}
634
		}
635
	}
636
	pspDebugScreenSetXY(0, 1 + 3 + incr + 1);
637
	int err = sceNetApctlConnect(choice[cur]);
638
	if(err != 0) {
639
		printf("Apctl initialization failure\n");
640
		while(running) sceKernelDelayThread(50 * 1000);
641
		sceKernelExitGame();
642
	} else {
643
		printf("Apctl initialization successful\n");
644
	}
645
	printf("Apctl connecting\n");
646
	while(1) {
647
		int state;
648
		err = sceNetApctlGetState(&state);
649
		if(err != 0) {
650
			printf("Apctl getting status failure\n");
651
			while(running) sceKernelDelayThread(50 * 1000);
652
			sceKernelExitGame();
653
		}
654
		if(state == 4) {
655
			break;
656
		}
657
		sceKernelDelayThread(50 * 1000);
658
	}
659
	union SceNetApctlInfo info;
660
	if(sceNetApctlGetInfo(8, &info) != 0) {
661
		printf("Got an unknown IP\n");
662
		while(running) sceKernelDelayThread(50 * 1000);
663
		sceKernelExitGame();
664
	}
665
	printf("Connected, My IP is %s\n", info.ip);
187 nishi 666
#elif defined(__PPU__)
191 nishi 667
	int i;
668
	ctx = init_screen();
669
	int w, h;
670
	get_resolution(&w, &h);
671
	tt_width = w / 6;
672
	tt_height = h / 8;
673
	tvram = malloc((w / 6) * (h / 8));
674
	for(i = 0; i < BUFFERS; i++) make_buffer(&buffers[i], i);
675
	flip(ctx, BUFFERS - 1);
676
	sys_ppu_thread_t id;
677
	sysThreadCreate(&id, text_thread, NULL, 1500, 0x1000, THREAD_JOINABLE, "TextThread");
187 nishi 678
	printf("PS3 Bootstrap, Tewi/%s\n", tw_get_version());
197 nishi 679
	show_png();
187 nishi 680
	netInitialize();
189 nishi 681
#elif defined(__ps2sdk__)
682
	SifInitRpc(0);
200 nishi 683
	while(!SifIopReset("", 0))
684
		;
685
	while(!SifIopSync())
686
		;
189 nishi 687
	init_scr();
688
	scr_printf("PS2 Bootstrap, Tewi/%s\n", tw_get_version());
200 nishi 689
	SleepThread();
182 nishi 690
#endif
212 nishi 691
	st = startup(argc, argv);
183 nishi 692
	if(st != -1) {
693
#ifdef _PSP
694
		printf("Error code %d\n", st);
695
		while(running) sceKernelDelayThread(50 * 1000);
696
		sceKernelExitGame();
697
#else
191 nishi 698
#ifdef __PPU__
699
		printf("Error code %d\n", st);
700
		while(1)
701
			;
702
#endif
183 nishi 703
		return st;
704
#endif
705
	}
62 nishi 706
	tw_server_loop();
707
#endif
183 nishi 708
#ifdef _PSP
709
	sceKernelExitGame();
710
#endif
168 nishi 711
	return 0;
62 nishi 712
}
244 nishi 713
#endif
62 nishi 714
 
70 nishi 715
int startup(int argc, char** argv) {
3 nishi 716
	int i;
212 nishi 717
	char* r;
257 nishi 718
#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__)
206 nishi 719
	char* confpath = cm_strdup(PREFIX "/etc/tewi.conf");
720
	char* regpath = get_registry("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Tewi HTTPd", "InstallDir");
721
	if(regpath != NULL) {
722
		free(confpath);
723
		confpath = cm_strcat(regpath, "/etc/tewi.conf");
724
		free(regpath);
725
	}
726
#else
18 nishi 727
	const char* confpath = PREFIX "/etc/tewi.conf";
206 nishi 728
#endif
70 nishi 729
	if(argv != NULL) {
62 nishi 730
		for(i = 1; i < argc; i++) {
731
			if(argv[i][0] == '-') {
732
				if(strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0) {
733
					if(!cm_do_log) {
734
						cm_do_log = true;
70 nishi 735
#ifndef NO_SSL
62 nishi 736
						cm_log("", "This is Tewi HTTPd, version %s, using %s", tw_get_version(), OPENSSL_VERSION_TEXT);
70 nishi 737
#else
62 nishi 738
						cm_log("", "This is Tewi HTTPd, version %s", tw_get_version());
70 nishi 739
#endif
62 nishi 740
					} else {
741
						cm_do_log = true;
742
					}
743
				} else if(strcmp(argv[i], "--config") == 0 || strcmp(argv[i], "-C") == 0) {
744
					i++;
745
					if(argv[i] == NULL) {
183 nishi 746
						STDERR_LOG("Missing argument\n");
62 nishi 747
						return 1;
748
					}
749
					confpath = argv[i];
182 nishi 750
#ifndef _PSP
117 nishi 751
				} else if(strcmp(argv[i], "--logfile") == 0 || strcmp(argv[i], "-l") == 0) {
752
					i++;
753
					if(argv[i] == NULL) {
183 nishi 754
						STDERR_LOG("Missing argument\n");
117 nishi 755
						return 1;
756
					}
757
					if(logfile != NULL && logfile != stderr) {
758
						fclose(logfile);
759
					}
760
					logfile = fopen(argv[i], "a");
761
					if(logfile == NULL) {
183 nishi 762
						STDERR_LOG("Failed to open logfile\n");
117 nishi 763
						return 1;
764
					}
182 nishi 765
#endif
62 nishi 766
				} else if(strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-V") == 0) {
767
					printf("Tewi HTTPd Tewi/%s\n", tw_get_version());
768
					printf("Under public domain.\n");
769
					printf("Original by 2024 Nishi\n");
770
					printf("\n");
771
					printf("Usage: %s [--config|-C config] [--verbose|-v] [--version|-V]\n", argv[0]);
119 nishi 772
					printf("--config  | -C config      : Specify config\n");
182 nishi 773
#ifndef _PSP
119 nishi 774
					printf("--logfile | -l logfile     : Specify logfile\n");
182 nishi 775
#endif
119 nishi 776
					printf("--verbose | -v             : Verbose mode\n");
777
					printf("--version | -V             : Version information\n");
62 nishi 778
					return 0;
3 nishi 779
				} else {
183 nishi 780
					STDERR_LOG("Unknown option: %s\n", argv[i]);
4 nishi 781
					return 1;
782
				}
3 nishi 783
			}
784
		}
785
	}
6 nishi 786
	tw_config_init();
18 nishi 787
	if(tw_config_read(confpath) != 0) {
183 nishi 788
		STDERR_LOG("Could not read the config\n");
4 nishi 789
		return 1;
790
	}
8 nishi 791
	if(tw_server_init() != 0) {
183 nishi 792
		STDERR_LOG("Could not initialize the server\n");
8 nishi 793
		return 1;
794
	}
18 nishi 795
	sprintf(tw_server, "Tewi/%s (%s)%s", tw_get_version(), tw_get_platform(), config.extension == NULL ? "" : config.extension);
212 nishi 796
	r = cm_strcat(tw_server, " running...");
62 nishi 797
	cm_force_log(r);
798
	free(r);
219 nishi 799
#if !defined(__MINGW32__) && !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__WATCOMC__)
16 nishi 800
	signal(SIGCHLD, SIG_IGN);
90 nishi 801
	signal(SIGPIPE, SIG_IGN);
253 nishi 802
#elif !defined(BUILD_GUI)
50 nishi 803
	SetConsoleTitle(tw_server);
16 nishi 804
#endif
62 nishi 805
	return -1;
3 nishi 806
}