Subversion Repositories Tewi

Rev

Rev 219 | Rev 249 | 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 244 2024-10-03 20:04:15Z nishi $ */
2
 
16 nishi 3
#define SOURCE
4
 
43 nishi 5
#include "../config.h"
6
 
215 nishi 7
#ifdef __BORLANDC__
8
 
9
#pragma resource "tewi_bcc.res"
244 nishi 10
#pragma resource "gui_bcc.res"
215 nishi 11
 
12
#endif
13
 
14
#if !defined(_MSC_VER) && !defined(__BORLANDC__)
189 nishi 15
#include <unistd.h>
212 nishi 16
#endif
3 nishi 17
#include <stdio.h>
18
#include <stdbool.h>
19
#include <string.h>
16 nishi 20
#include <signal.h>
116 nishi 21
#include <stdlib.h>
3 nishi 22
 
43 nishi 23
#ifndef NO_SSL
6 nishi 24
#include <openssl/opensslv.h>
43 nishi 25
#endif
6 nishi 26
 
3 nishi 27
#include <cm_log.h>
62 nishi 28
#include <cm_string.h>
3 nishi 29
 
4 nishi 30
#include "tw_config.h"
8 nishi 31
#include "tw_server.h"
3 nishi 32
#include "tw_version.h"
33
 
244 nishi 34
#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
51 nishi 35
#include <windows.h>
36
#endif
37
 
182 nishi 38
#ifdef _PSP
39
#include <pspkernel.h>
40
#include <pspdebug.h>
183 nishi 41
#include <pspsdk.h>
42
#include <psputility.h>
43
#include <pspctrl.h>
44
#include <pspnet_apctl.h>
45
#include <pspwlan.h>
182 nishi 46
 
47
PSP_MODULE_INFO("Tewi HTTPd", PSP_MODULE_USER, 1, 1);
48
PSP_MAIN_THREAD_ATTR(PSP_THREAD_ATTR_USER);
49
 
50
#define printf(...) pspDebugScreenPrintf(__VA_ARGS__)
183 nishi 51
#define STDERR_LOG(...) pspDebugScreenPrintf(__VA_ARGS__)
189 nishi 52
#elif defined(__ps2sdk__)
53
#include <debug.h>
200 nishi 54
#include <iopcontrol.h>
189 nishi 55
#include <sifrpc.h>
200 nishi 56
#include <kernel.h>
189 nishi 57
 
58
#define printf(...) scr_printf(__VA_ARGS__)
59
#define STDERR_LOG(...) scr_printf(__VA_ARGS__)
191 nishi 60
#elif defined(__PPU__)
61
#include <rsx/gcm_sys.h>
62
#include <rsx/rsx.h>
63
#include <sysutil/video.h>
64
#include <malloc.h>
65
#include <sys/thread.h>
66
#include <stdarg.h>
197 nishi 67
#include <png.h>
191 nishi 68
 
69
#define printf(...) tt_printf(__VA_ARGS__)
70
#define STDERR_LOG(...) tt_printf(__VA_ARGS__)
215 nishi 71
#elif defined(_MSC_VER) || defined(__BORLANDC__)
213 nishi 72
void STDERR_LOG(const char* format, ...) {
212 nishi 73
	va_list args;
74
	va_start(args, format);
75
	vfprintf(stderr, format, args);
76
	va_end(args);
77
}
183 nishi 78
#else
79
#define STDERR_LOG(...) fprintf(stderr, __VA_ARGS__)
182 nishi 80
#endif
81
 
3 nishi 82
extern bool cm_do_log;
18 nishi 83
extern struct tw_config config;
62 nishi 84
extern FILE* logfile;
3 nishi 85
 
18 nishi 86
char tw_server[2048];
87
 
62 nishi 88
int startup(int argc, char** argv);
89
 
212 nishi 90
#if defined(__MINGW32__) || defined(_MSC_VER)
206 nishi 91
char* get_registry(const char* main, const char* sub) {
208 nishi 92
	DWORD bufsize = 512;
93
	HKEY handle;
94
	char* value = malloc(513);
95
	int err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, main, 0, KEY_QUERY_VALUE, &handle);
206 nishi 96
	if(err == ERROR_SUCCESS) {
208 nishi 97
		err = RegQueryValueEx(handle, sub, NULL, NULL, value, &bufsize);
98
		if(err != ERROR_SUCCESS) {
99
			free(value);
100
			RegCloseKey(handle);
101
			return NULL;
102
		}
103
		RegCloseKey(handle);
206 nishi 104
		return value;
105
	} else {
106
		free(value);
107
		return NULL;
108
	}
109
}
110
#endif
111
 
62 nishi 112
#ifdef SERVICE
113
SERVICE_STATUS status;
114
SERVICE_STATUS_HANDLE status_handle;
115
 
70 nishi 116
void WINAPI servhandler(DWORD control) {
117
	switch(control) {
118
	case SERVICE_CONTROL_STOP:
119
	case SERVICE_CONTROL_SHUTDOWN:
120
		status.dwCurrentState = SERVICE_STOP_PENDING;
121
		break;
62 nishi 122
	}
123
	SetServiceStatus(status_handle, &status);
124
}
125
 
70 nishi 126
void WINAPI servmain(DWORD argc, LPSTR* argv) {
206 nishi 127
	char* path = get_registry("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Tewi HTTPd", "InstallDir");
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;
147
	int 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
 
244 nishi 528
#if !defined(BUILD_GUI) || !(defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__))
3 nishi 529
int main(int argc, char** argv) {
212 nishi 530
	int st;
62 nishi 531
	logfile = stderr;
532
#ifdef SERVICE
533
	SERVICE_TABLE_ENTRY table[] = {{"Tewi HTTPd", servmain}, {NULL, NULL}};
534
	StartServiceCtrlDispatcher(table);
535
#else
182 nishi 536
#ifdef _PSP
537
	pspDebugScreenInit();
538
	pspDebugScreenSetXY(0, 0);
183 nishi 539
	printf("PSP Bootstrap, Tewi/%s\n", tw_get_version());
540
	int thid = sceKernelCreateThread("update_thread", psp_callback_thread, 0x11, 0xfa0, 0, NULL);
541
	if(thid >= 0) {
542
		sceKernelStartThread(thid, 0, NULL);
543
	} else {
544
		printf("Failed to start thread\n");
545
		while(running) sceKernelDelayThread(50 * 1000);
546
		sceKernelExitGame();
547
	}
548
	sceCtrlSetSamplingCycle(0);
549
	sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
550
	sceUtilityLoadNetModule(PSP_NET_MODULE_COMMON);
551
	sceUtilityLoadNetModule(PSP_NET_MODULE_INET);
552
	if(pspSdkInetInit()) {
553
		printf("Could not init the network\n");
554
		while(running) sceKernelDelayThread(50 * 1000);
555
		sceKernelExitGame();
556
	} else {
557
		printf("Network initialization successful\n");
558
	}
559
	if(sceWlanGetSwitchState() != 1) {
560
		printf("Turn the Wi-Fi switch on\n");
561
		while(sceWlanGetSwitchState() != 1) {
562
			sceKernelDelayThread(1000 * 1000);
563
		}
564
	} else {
565
		printf("Wi-Fi is turned on\n");
566
	}
567
	int i;
568
	int choice[100];
569
	int incr = 0;
570
	int last = 0;
571
	int cur = 0;
572
	for(i = 1; i < 100; i++) {
573
		choice[i - 1] = 0;
574
		netData name;
575
		netData data;
576
		if(sceUtilityCheckNetParam(i) != 0) continue;
577
		choice[incr++] = i;
578
		pspDebugScreenSetXY(0, 1 + 3 + incr - 1);
579
		if(incr == 1) printf("> ");
580
		pspDebugScreenSetXY(2, 1 + 3 + incr - 1);
581
		sceUtilityGetNetParam(i, 0, &name);
582
		sceUtilityGetNetParam(i, 1, &data);
583
		printf("SSID=%s", data.asString);
584
		sceUtilityGetNetParam(i, 4, &data);
585
		if(data.asString[0]) {
586
			sceUtilityGetNetParam(i, 5, &data);
587
			printf(" IPADDR=%s\n", data.asString);
588
		} else {
589
			printf(" DHCP\n");
590
		}
591
	}
592
	int press = 0;
593
	while(1) {
594
		if(!running) {
595
			sceKernelExitGame();
596
		}
597
		SceCtrlData c;
598
		sceCtrlReadBufferPositive(&c, 1);
599
		press = 0;
600
		if(c.Buttons & PSP_CTRL_DOWN) {
601
			if(cur < incr - 1) {
602
				cur++;
603
			}
604
			press = 1;
605
		} else if(c.Buttons & PSP_CTRL_UP) {
606
			if(cur > 0) {
607
				cur--;
608
			}
609
			press = -1;
610
		} else if(c.Buttons & PSP_CTRL_START) {
611
			break;
612
		}
613
		if(last != cur) {
614
			pspDebugScreenSetXY(0, 1 + 3 + last);
615
			printf("  ");
616
			pspDebugScreenSetXY(0, 1 + 3 + cur);
617
			printf("> ");
618
			last = cur;
619
		}
620
		if(press != 0) {
621
			while(1) {
622
				SceCtrlData c;
623
				sceCtrlReadBufferPositive(&c, 1);
624
				if(press == 1) {
625
					if(!(c.Buttons & PSP_CTRL_DOWN)) break;
626
				} else if(press == -1) {
627
					if(!(c.Buttons & PSP_CTRL_UP)) break;
628
				}
629
			}
630
		}
631
	}
632
	pspDebugScreenSetXY(0, 1 + 3 + incr + 1);
633
	int err = sceNetApctlConnect(choice[cur]);
634
	if(err != 0) {
635
		printf("Apctl initialization failure\n");
636
		while(running) sceKernelDelayThread(50 * 1000);
637
		sceKernelExitGame();
638
	} else {
639
		printf("Apctl initialization successful\n");
640
	}
641
	printf("Apctl connecting\n");
642
	while(1) {
643
		int state;
644
		err = sceNetApctlGetState(&state);
645
		if(err != 0) {
646
			printf("Apctl getting status failure\n");
647
			while(running) sceKernelDelayThread(50 * 1000);
648
			sceKernelExitGame();
649
		}
650
		if(state == 4) {
651
			break;
652
		}
653
		sceKernelDelayThread(50 * 1000);
654
	}
655
	union SceNetApctlInfo info;
656
	if(sceNetApctlGetInfo(8, &info) != 0) {
657
		printf("Got an unknown IP\n");
658
		while(running) sceKernelDelayThread(50 * 1000);
659
		sceKernelExitGame();
660
	}
661
	printf("Connected, My IP is %s\n", info.ip);
187 nishi 662
#elif defined(__PPU__)
191 nishi 663
	int i;
664
	ctx = init_screen();
665
	int w, h;
666
	get_resolution(&w, &h);
667
	tt_width = w / 6;
668
	tt_height = h / 8;
669
	tvram = malloc((w / 6) * (h / 8));
670
	for(i = 0; i < BUFFERS; i++) make_buffer(&buffers[i], i);
671
	flip(ctx, BUFFERS - 1);
672
	sys_ppu_thread_t id;
673
	sysThreadCreate(&id, text_thread, NULL, 1500, 0x1000, THREAD_JOINABLE, "TextThread");
187 nishi 674
	printf("PS3 Bootstrap, Tewi/%s\n", tw_get_version());
197 nishi 675
	show_png();
187 nishi 676
	netInitialize();
189 nishi 677
#elif defined(__ps2sdk__)
678
	SifInitRpc(0);
200 nishi 679
	while(!SifIopReset("", 0))
680
		;
681
	while(!SifIopSync())
682
		;
189 nishi 683
	init_scr();
684
	scr_printf("PS2 Bootstrap, Tewi/%s\n", tw_get_version());
200 nishi 685
	SleepThread();
182 nishi 686
#endif
212 nishi 687
	st = startup(argc, argv);
183 nishi 688
	if(st != -1) {
689
#ifdef _PSP
690
		printf("Error code %d\n", st);
691
		while(running) sceKernelDelayThread(50 * 1000);
692
		sceKernelExitGame();
693
#else
191 nishi 694
#ifdef __PPU__
695
		printf("Error code %d\n", st);
696
		while(1)
697
			;
698
#endif
183 nishi 699
		return st;
700
#endif
701
	}
62 nishi 702
	tw_server_loop();
703
#endif
183 nishi 704
#ifdef _PSP
705
	sceKernelExitGame();
706
#endif
168 nishi 707
	return 0;
62 nishi 708
}
244 nishi 709
#endif
62 nishi 710
 
70 nishi 711
int startup(int argc, char** argv) {
3 nishi 712
	int i;
212 nishi 713
	char* r;
714
#if defined(__MINGW32__) || defined(_MSC_VER)
206 nishi 715
	char* confpath = cm_strdup(PREFIX "/etc/tewi.conf");
716
	char* regpath = get_registry("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Tewi HTTPd", "InstallDir");
717
	if(regpath != NULL) {
718
		free(confpath);
719
		confpath = cm_strcat(regpath, "/etc/tewi.conf");
720
		free(regpath);
721
	}
722
#else
18 nishi 723
	const char* confpath = PREFIX "/etc/tewi.conf";
206 nishi 724
#endif
70 nishi 725
	if(argv != NULL) {
62 nishi 726
		for(i = 1; i < argc; i++) {
727
			if(argv[i][0] == '-') {
728
				if(strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0) {
729
					if(!cm_do_log) {
730
						cm_do_log = true;
70 nishi 731
#ifndef NO_SSL
62 nishi 732
						cm_log("", "This is Tewi HTTPd, version %s, using %s", tw_get_version(), OPENSSL_VERSION_TEXT);
70 nishi 733
#else
62 nishi 734
						cm_log("", "This is Tewi HTTPd, version %s", tw_get_version());
70 nishi 735
#endif
62 nishi 736
					} else {
737
						cm_do_log = true;
738
					}
739
				} else if(strcmp(argv[i], "--config") == 0 || strcmp(argv[i], "-C") == 0) {
740
					i++;
741
					if(argv[i] == NULL) {
183 nishi 742
						STDERR_LOG("Missing argument\n");
62 nishi 743
						return 1;
744
					}
745
					confpath = argv[i];
182 nishi 746
#ifndef _PSP
117 nishi 747
				} else if(strcmp(argv[i], "--logfile") == 0 || strcmp(argv[i], "-l") == 0) {
748
					i++;
749
					if(argv[i] == NULL) {
183 nishi 750
						STDERR_LOG("Missing argument\n");
117 nishi 751
						return 1;
752
					}
753
					if(logfile != NULL && logfile != stderr) {
754
						fclose(logfile);
755
					}
756
					logfile = fopen(argv[i], "a");
757
					if(logfile == NULL) {
183 nishi 758
						STDERR_LOG("Failed to open logfile\n");
117 nishi 759
						return 1;
760
					}
182 nishi 761
#endif
62 nishi 762
				} else if(strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-V") == 0) {
763
					printf("Tewi HTTPd Tewi/%s\n", tw_get_version());
764
					printf("Under public domain.\n");
765
					printf("Original by 2024 Nishi\n");
766
					printf("\n");
767
					printf("Usage: %s [--config|-C config] [--verbose|-v] [--version|-V]\n", argv[0]);
119 nishi 768
					printf("--config  | -C config      : Specify config\n");
182 nishi 769
#ifndef _PSP
119 nishi 770
					printf("--logfile | -l logfile     : Specify logfile\n");
182 nishi 771
#endif
119 nishi 772
					printf("--verbose | -v             : Verbose mode\n");
773
					printf("--version | -V             : Version information\n");
62 nishi 774
					return 0;
3 nishi 775
				} else {
183 nishi 776
					STDERR_LOG("Unknown option: %s\n", argv[i]);
4 nishi 777
					return 1;
778
				}
3 nishi 779
			}
780
		}
781
	}
6 nishi 782
	tw_config_init();
18 nishi 783
	if(tw_config_read(confpath) != 0) {
183 nishi 784
		STDERR_LOG("Could not read the config\n");
4 nishi 785
		return 1;
786
	}
8 nishi 787
	if(tw_server_init() != 0) {
183 nishi 788
		STDERR_LOG("Could not initialize the server\n");
8 nishi 789
		return 1;
790
	}
18 nishi 791
	sprintf(tw_server, "Tewi/%s (%s)%s", tw_get_version(), tw_get_platform(), config.extension == NULL ? "" : config.extension);
212 nishi 792
	r = cm_strcat(tw_server, " running...");
62 nishi 793
	cm_force_log(r);
794
	free(r);
219 nishi 795
#if !defined(__MINGW32__) && !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__WATCOMC__)
16 nishi 796
	signal(SIGCHLD, SIG_IGN);
90 nishi 797
	signal(SIGPIPE, SIG_IGN);
50 nishi 798
#else
799
	SetConsoleTitle(tw_server);
16 nishi 800
#endif
62 nishi 801
	return -1;
3 nishi 802
}