9os

Experimental kernel using plan9 ideas for embedded device
git clone git://git.simple-cc.org/9os
Log | Files | Refs | README | LICENSE

dlang.c (6880B)


      1 #include <os9/os9.h>
      2 
      3 #include <libk.h>
      4 
      5 #include <ctype.h>
      6 #include <errno.h>
      7 #include <setjmp.h>
      8 #include <stdarg.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 
     12 #define PREFIX	"> "
     13 #define PREFIX2 "# "
     14 #define NR_ARGC_MAX 5
     15 
     16 struct args {
     17 	char *argv[NR_ARGC_MAX];
     18 	int argc;
     19 	int status;
     20 };
     21 
     22 struct cmd {
     23 	char *name;
     24 	char *helpmsg;
     25 	int (*eval)(const struct cmd *, struct args *);
     26 	unsigned char min;
     27 	unsigned char max;
     28 };
     29 
     30 unsigned in_debug;
     31 jmp_buf dbgrecover;
     32 
     33 static const struct cmd cmds[];
     34 
     35 static void
     36 error(char *fmt, ...)
     37 {
     38 	va_list va;
     39 
     40 	va_start(va, fmt);
     41 	kprint(PREFIX "ERR ");
     42 	kvprint(fmt, va);
     43 	kprint("\n");
     44 	longjmp(dbgrecover, 1);
     45 }
     46 
     47 static void
     48 ready(void)
     49 {
     50 	kprint(PREFIX "READY\n");
     51 }
     52 
     53 /* Get cmd struct for named cmd */
     54 static const struct cmd *
     55 get_cmd(char *name)
     56 {
     57 	const struct cmd *cmd;
     58 
     59 	for (cmd = cmds; cmd->name; cmd++) {
     60 		if (strcmp(cmd->name, name) == 0)
     61 			return cmd;
     62 	}
     63 	return NULL;
     64 }
     65 
     66 static int
     67 do_exit(const struct cmd *cmd, struct args *args)
     68 {
     69 	args->status = 0;
     70 	if (args->argc == 2)
     71 		args->status = atoi(args->argv[1]);
     72 	return -1;
     73 }
     74 
     75 static int
     76 do_help(const struct cmd *cmd, struct args *args)
     77 {
     78 	for (cmd = cmds; cmd->name; cmd++) {
     79 		char *s = cmd->helpmsg;
     80 		kprint(PREFIX2 "%s\n", s);
     81 	}
     82 	return 0;
     83 }
     84 
     85 static int
     86 do_read(const struct cmd *cmd, struct args *args)
     87 {
     88 	int n, ch;
     89 	Chan *c;
     90 	char buf[100], *bp;
     91 
     92 	if ((c = namec(args->argv[1], O_READ)) == NULL)
     93 		goto err;
     94 
     95 	ch = -1;
     96 	kprint(PREFIX2);
     97 	while ((n = chanread(c, buf, sizeof(buf))) > 0) {
     98 		for (bp = buf; bp < &buf[n]; bp++) {
     99 			if (ch == '\n')
    100 				kprint(PREFIX2);
    101 			ch = *bp;
    102 			kprint("%c", ch);
    103 		}
    104 	}
    105 	if (ch != '\n')
    106 		kprint("\n");
    107 
    108 	if (chanclose(c) < 0 || n < 0)
    109 		goto err;
    110 
    111 	return 0;
    112 
    113 err:
    114 	kprint(PREFIX "ERR read: %e\n");
    115 	return 0;
    116 }
    117 
    118 static int
    119 do_ls(const struct cmd *cmd, struct args *args)
    120 {
    121 	int n;
    122 	Chan *c;
    123 	Dir dentry;
    124 	unsigned char buf[DIRLEN];
    125 
    126 	if ((c = namec(args->argv[1], O_READ)) == NULL)
    127 		goto err;
    128 
    129 	while ((n = chanread(c, buf, DIRLEN)) > 0) {
    130 		if (p9todir(&dentry, buf, n) < 0)
    131 			goto err;
    132 		kprint(PREFIX2 "%s\n", dentry.name);
    133 	}
    134 
    135 	if (chanclose(c) ||  n < 0)
    136 		goto err;
    137 
    138 	return 0;
    139 
    140 err:
    141 	kprint(PREFIX "ERR ls:%e\n");
    142 	return 0;
    143 }
    144 
    145 static int
    146 do_write(const struct cmd *cmd, struct args *args)
    147 {
    148 	int i, len, offset, n;
    149 	Chan *c;
    150 	char *s, buffer[LINELEN];
    151 
    152 	if ((c = namec(args->argv[1], O_WRITE)) == NULL)
    153 		goto err;
    154 
    155 	offset = 0;
    156 	for (i = 2; i < args->argc; i++) {
    157 		s = args->argv[i];
    158 		len = strlen(s);
    159 		if (len + offset >= LINELEN-2)
    160 			error("line too long");
    161 		memcpy(buffer + offset, s, len);
    162 		offset += len;
    163 		buffer[offset++] = ' ';
    164 	}
    165 	buffer[offset] = '\n';
    166 	n = chanwrite(c, buffer, offset);
    167 
    168 	if (chanclose(c) < 0 || n < 0)
    169 		goto err;
    170 
    171 	return 0;
    172 err:
    173 	kprint(PREFIX "ERR write:%e\n");
    174 	return 0;
    175 }
    176 
    177 static int
    178 do_stat(const struct cmd *cmd, struct args *args)
    179 {
    180 	Dir dir;
    181 
    182 	if (dirstat(args->argv[1], &dir) < 0)
    183 		goto err;
    184 	kprint(PREFIX2 "name: %s\n"
    185 	       PREFIX2 "length: %ld\n"
    186 	       PREFIX2 "mode: %x\n"
    187 	       PREFIX2 "type: %d\n"
    188 	       PREFIX2 "dev: %d\n"
    189 	       PREFIX2 "qid: %x,%lx,%llx\n",
    190 	       dir.name,
    191 	       dir.length,
    192 	       dir.mode,
    193 	       dir.type,
    194 	       dir.dev,
    195 	       dir.qid.type, dir.qid.vers, dir.qid.path);
    196 
    197 	return 0;
    198 
    199 err:
    200 	kprint(PREFIX "ERR stat:%e\n");
    201 	return 0;
    202 }
    203 
    204 static int
    205 do_bind(const struct cmd *cmd, struct args *args)
    206 {
    207 	if (bind(args->argv[1], args->argv[2]) < 0)
    208 		kprint(PREFIX "ERR bind:%e\n");
    209 	return 0;
    210 }
    211 
    212 static int
    213 do_mount(const struct cmd *cmd, struct args *args)
    214 {
    215 	if (mount(args->argv[1], args->argv[2], args->argv[3]) < 0)
    216 		kprint(PREFIX "ERR mount:%e\n");
    217 	return 0;
    218 }
    219 
    220 static int
    221 do_x(const struct cmd *cmd, struct args *args)
    222 {
    223 	char *p, *s;
    224 	int n;
    225 	void *addr;
    226 	size_t len;
    227 	uint16_t *u16;
    228 	uint32_t *u32;
    229 	uint64_t *u64;
    230 
    231 	s = args->argv[1];
    232 	if ((p = strchr(s, '/'))  == NULL)
    233 		goto badfmt;
    234 	*p++ = '\0';
    235 
    236 	addr = (void *) strtoll(s, NULL, 0);
    237 	n = atoi(p);
    238 	if (n == 0)
    239 		n = 1;
    240 
    241 	len = strspn(p, "0123456789");
    242 	switch (p[len]) {
    243 	case 'x':
    244 		u16 = addr;
    245 		while (n-- > 0)
    246 			kprint(PREFIX2 "%x\n", (int) *u16++);
    247 		return 0;
    248 	case 'X':
    249 		u32 = addr;
    250 		while (n-- > 0)
    251 			kprint(PREFIX2 "%lx\n", (long) *u32++);
    252 		return 0;
    253 	case 'Y':
    254 		u64 = addr;
    255 		while (n-- > 0)
    256 			kprint(PREFIX2 "%x\n", (long long) *u64++);
    257 		return 0;
    258 	default:
    259 		goto badfmt;
    260 	}
    261 
    262 badfmt:
    263 	kprint(PREFIX "ERR x: bad format\n");
    264 	return 0;
    265 }
    266 
    267 static const struct cmd *
    268 parse_cmd(char *buf, struct args *args)
    269 {
    270 	char *p;
    271 	const struct cmd *cmd;
    272 	const static char ws[] = " \t\r";
    273 
    274 	args->argc = 0;
    275 	for (p = strtok(buf, ws); p; p = strtok(NULL, ws)) {
    276 		if (args->argc == NR_ARGC_MAX)
    277 			error("too many parameters");
    278 		args->argv[args->argc++] = p;
    279 	}
    280 
    281 	if (args->argc == 0)
    282 		return NULL;
    283 
    284 	if ((cmd = get_cmd(args->argv[0])) == NULL)
    285 		error("%s: not found", args->argv[0]);
    286 
    287 	return cmd;
    288 }
    289 
    290 static int
    291 run(struct args *args)
    292 {
    293 	const struct cmd *cmd;
    294 	size_t len;
    295 	char buffer[LINELEN];
    296 
    297 	if (kgets(buffer, sizeof(buffer)) == NULL) {
    298 		args->status = 1;
    299 		return -1;
    300 	}
    301 
    302 	if ((len = strlen(buffer)) != 0) {
    303 		if (buffer[len-1] != '\n')
    304 			error("line too long");
    305 		buffer[len-1] = '\0';
    306 		cmd = parse_cmd(buffer, args);
    307 		if (cmd) {
    308 			int (*fn)(const struct cmd *, struct args *);
    309 			void *bp;
    310 
    311 			if (args->argc < cmd->min || args->argc > cmd->max)
    312 				error(cmd->helpmsg);
    313 			bp = cmd->eval;
    314 			fn = (int (*)(const struct cmd *, struct args *)) bp;
    315 			return (*fn)(cmd, args);
    316 		}
    317 	}
    318 
    319 	return 0;
    320 }
    321 
    322 int
    323 debug(void)
    324 {
    325 	struct args args;
    326 
    327 	kprint("begin debug language interface\n");
    328 	in_debug = 1;
    329 	setjmp(dbgrecover);
    330 
    331 	for (ready(); !run(&args); ready())
    332 		;
    333 	kprint("end debug language interface\n");
    334 	in_debug = 0;
    335 
    336 	return args.status;
    337 }
    338 
    339 /*
    340  * definition of arrays
    341  */
    342 static const struct cmd cmds[] = {
    343 	{
    344 		.name = "exit",
    345 		.eval = do_exit,
    346 		.min = 1,
    347 		.max = 2,
    348 		.helpmsg = "Exit debug environment: exit [status]",
    349 	},
    350 	{
    351 		.name = "help",
    352 		.eval = do_help,
    353 		.min = 1,
    354 		.max = 1,
    355 		.helpmsg = "Print this help menu: help",
    356 	},
    357 	{
    358 		.name = "ls",
    359 		.eval = do_ls,
    360 		.min = 2,
    361 		.max = 2,
    362 		.helpmsg = "List content of a directory: ls path",
    363 	},
    364 	{
    365 		.name = "read",
    366 		.eval = do_read,
    367 		.min = 2,
    368 		.max = 2,
    369 		.helpmsg = "Read content from a file: read path",
    370 	},
    371 	{
    372 		.name = "write",
    373 		.eval = do_write,
    374 		.min = 3,
    375 		.max = NR_ARGC_MAX,
    376 		.helpmsg = "Write content to a file: write path string ...",
    377 	},
    378 	{
    379 		.name = "stat",
    380 		.eval = do_stat,
    381 		.min = 2,
    382 		.max = 2,
    383 		.helpmsg = "Display stat attribute: stat path",
    384 	},
    385 	{
    386 		.name = "bind",
    387 		.eval = do_bind,
    388 		.min = 3,
    389 		.max = 3,
    390 		.helpmsg = "bind one directory in other: bind from to",
    391 	},
    392 	{
    393 		.name = "mount",
    394 		.eval = do_mount,
    395 		.min = 4,
    396 		.max = 4,
    397 		.helpmsg = "mount one directory in other: mount from to spec",
    398 	},
    399 	{
    400 		.name = "x",
    401 		.eval = do_x,
    402 		.min = 2,
    403 		.max = 2,
    404 		.helpmsg = "Examine memory: x addr/fmt",
    405 	},
    406 	{
    407 		.name = NULL
    408 	}
    409 };