parseopts.c (4021B)
1 #include <unistd.h> 2 #include <stdint.h> 3 #include <string.h> 4 #include <unistd.h> 5 6 static int begins_with(char * str, char * prefix) 7 { 8 while(*prefix) { 9 if(*str == '\0') return 0; 10 if(*str != *prefix) return 0; 11 str++; 12 prefix++; 13 } 14 return 1; 15 } 16 17 char * pr_u32(int32_t input) { 18 static char buf[9]; 19 const char *digits = "0123456789abcdef"; 20 int i=0; 21 22 buf[i] = digits[(input & 0xf0000000) >> 28]; 23 buf[i+1] = digits[(input & 0x0f000000) >> 24]; 24 if(buf[i] != '0' || buf[i+1] != '0') i+=2; 25 26 buf[i] = digits[(input & 0x00f00000) >> 20]; 27 buf[i+1] = digits[(input & 0x000f0000) >> 16]; 28 if(buf[i] != '0' || buf[i+1] != '0') i+=2; 29 30 buf[i] = digits[(input & 0x0000f000) >> 12]; 31 buf[i+1] = digits[(input & 0x00000f00) >> 8]; 32 if(buf[i] != '0' || buf[i+1] != '0') i+=2; 33 34 buf[i] = digits[(input & 0x000000f0) >> 4]; 35 buf[i+1] = digits[(input & 0x0000000f)]; 36 i+=2; 37 38 buf[i] ='\0'; 39 write(2, buf, i); 40 41 return buf; 42 } 43 44 45 void parseopts(char * cmdline, char **root, char **rootfstype) { 46 *root = 0; 47 *rootfstype = 0; 48 49 for(char *p = cmdline; *p; p++) { 50 if(begins_with(p, "root=")) { 51 *root = p + strlen("root="); 52 while(*p && (*p != ' ')) p++; 53 54 if(*p) { 55 *p = '\0'; 56 p++; 57 }; 58 }; 59 if(begins_with(p, "rootfstype=")) { 60 *rootfstype = p + strlen("rootfstype="); 61 while(*p && (*p != ' ')) p++; 62 if(*p) { 63 *p = '\0'; 64 p++; 65 }; 66 }; 67 }; 68 } 69 70 #ifdef TESTS 71 #include <assert.h> 72 #include <stdio.h> 73 #include <stdlib.h> 74 75 // cc -DTESTS -o parseopts parseopts.c && ./parseopts 76 77 #define die(fmt, ...) do { printf(fmt, __VA_ARGS__); exit(1); } while(0) 78 #define S(x) #x 79 #define expect_equal(actual, expected) \ 80 if(!actual || strcmp(actual, expected)) die("%d: expected \"%s\", got \"%s\"", __LINE__, expected, actual); 81 82 83 int main() 84 { 85 char * root = "/dev/hda1"; 86 char * rootfstype = "xiafs"; 87 char *buf; 88 89 // finds root= and rootfstype= options 90 buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/ubi0_4 rootfstype=ubifs fw_devlink=off mtdparts=phram0:18M(rootfs) phram.phram=phram0,0x40400000,18874368,65536 root=/dev/mtdblock0 foo"); 91 parseopts(buf, &root, &rootfstype); 92 expect_equal(root, "/dev/mtdblock0"); 93 expect_equal(rootfstype, "ubifs"); 94 95 // in case of duplicates, chooses the latter 96 // also: works if the option is end of string 97 buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/ubi0_4 rootfstype=ubifs fw_devlink=off mtdparts=phram0:18M(rootfs) phram.phram=phram0,0x40400000,18874368,65536 root=/dev/mtdblock0"); 98 parseopts(buf, &root, &rootfstype); 99 expect_equal(root, "/dev/mtdblock0"); 100 expect_equal(rootfstype, "ubifs"); 101 102 // options may appear in either order 103 buf = strdup("liminix fw_devlink=off root=/dev/hda1 rootfstype=ubifs foo"); 104 parseopts(buf, &root, &rootfstype); 105 expect_equal(root, "/dev/hda1"); 106 expect_equal(rootfstype, "ubifs"); 107 108 buf = strdup("liminix rootfstype=ubifs fw_devlink=off root=/dev/hda1 foo"); 109 parseopts(buf, &root, &rootfstype); 110 expect_equal(rootfstype, "ubifs"); 111 expect_equal(root, "/dev/hda1"); 112 113 // provides NULL for missing options 114 buf = strdup("liminix rufustype=ubifs fw_devlink=off foot=/dev/hda1"); 115 parseopts(buf, &root, &rootfstype); 116 if(rootfstype) die("expected null rootfstype, got \"%s\"", rootfstype); 117 if(root) die("expected null root, got \"%s\"", root); 118 119 // provides empty strings for empty options 120 buf = strdup("liminix rootfstype= fw_devlink=off root= /dev/hda1"); 121 parseopts(buf, &root, &rootfstype); 122 if(strlen(rootfstype)) die("expected empty rootfstype, got \"%s\"", rootfstype); 123 if(strlen(root)) die("expected null root, got \"%s\"", root); 124 125 expect_equal("01", pr_u32(1)); 126 expect_equal("ab", pr_u32(0xab)); 127 expect_equal("0abc", pr_u32(0xabc)); 128 expect_equal("aabc", pr_u32(0xaabc)); 129 expect_equal("deadcafe", pr_u32(0xdeadcafe)); 130 } 131 132 #endif