shell-test.c (4683B)
1 #include <stdbool.h> 2 #include <stdint.h> 3 #include <stdio.h> 4 #include <string.h> 5 #ifdef _MSC_VER 6 # include <Windows.h> 7 # define usleep(usecs) Sleep(usecs/1000) 8 #else 9 # include <unistd.h> 10 #endif 11 12 static void flush_wait(void) 13 { 14 fflush(NULL); 15 usleep(10*1000); // Wait 10 ms. 16 } 17 18 static void help(void) 19 { 20 puts("Fake shell"); 21 puts(""); 22 puts("Usage:"); 23 puts(" shell-test --help"); 24 puts(" Prints this help to stdout."); 25 puts(" shell-test"); 26 puts(" shell-test EXE"); 27 puts(" Prints \"ready $ \" to stderr."); 28 puts(" shell-test -t {prompt text}"); 29 puts(" Prints \"{prompt text} $ \" to stderr."); 30 puts(" shell-test EXE \"prog args...\""); 31 puts(" Prints \"ready $ prog args...\\n\" to stderr."); 32 puts(" shell-test -t {prompt text} EXE \"prog args...\""); 33 puts(" Prints \"{prompt text} $ progs args...\" to stderr."); 34 puts(" shell-test EXECVP \"prog\" \"arg0\" args..."); 35 puts(" Executes prog arg0 args... using execvp()."); 36 puts(" shell-test REP N {text}"); 37 puts(" Prints \"{lnr}: {text}\\n\" to stdout N times, pausing every 100 lines."); 38 puts(" Example:"); 39 puts(" shell-test REP 97 \"foo bar\""); 40 puts(" 0: foo bar"); 41 puts(" ..."); 42 puts(" 96: foo bar"); 43 puts(" shell-test REPFAST N {text}"); 44 puts(" Like REP, but print as fast as possible and then exit immediately."); 45 puts(" shell-test INTERACT"); 46 puts(" Prints \"interact $ \" to stderr, and waits for \"exit\" input."); 47 puts(" shell-test EXIT {code}"); 48 puts(" Exits immediately with exit code \"{code}\"."); 49 } 50 51 int main(int argc, char **argv) 52 { 53 if (argc == 2 && strcmp(argv[1], "--help") == 0) { 54 help(); 55 } 56 57 #ifdef _MSC_VER 58 SetConsoleOutputCP(CP_UTF8); 59 #endif 60 61 if (argc >= 2) { 62 if (strcmp(argv[1], "-t") == 0) { 63 if (argc < 3) { 64 fprintf(stderr, "Missing prompt text for -t option\n"); 65 return 5; 66 } else { 67 fprintf(stderr, "%s $ ", argv[2]); 68 if (argc >= 5 && (strcmp(argv[3], "EXE") == 0)) { 69 fprintf(stderr, "%s\n", argv[4]); 70 } 71 } 72 } else if (strcmp(argv[1], "EXE") == 0) { 73 if (argc >= 3) { 74 fprintf(stderr, "ready $ %s\n", argv[2]); 75 } else { 76 fprintf(stderr, "ready $ "); 77 } 78 #ifndef _MSG_VER 79 } else if (strcmp(argv[1], "EXECVP") == 0) { 80 if (argc < 4) { 81 fprintf(stderr, "Not enough arguments for EXECVP\n"); 82 return 6; 83 } 84 execvp(argv[2], argv + 3); 85 #endif 86 } else if (strcmp(argv[1], "REP") == 0 || strcmp(argv[1], "REPFAST") == 0) { 87 bool fast = strcmp(argv[1], "REPFAST") == 0; 88 if (argc != 4) { 89 fprintf(stderr, "REP/REPFAST expects exactly 3 arguments\n"); 90 return 4; 91 } 92 int count = 0; 93 if (sscanf(argv[2], "%d", &count) != 1) { 94 fprintf(stderr, "Invalid count: %s\n", argv[2]); 95 return 4; 96 } 97 for (int i = 0; i < count; i++) { 98 printf("%d: %s\n", i, argv[3]); 99 if (!fast && i % 100 == 0) { 100 usleep(1000); // Wait 1 ms (simulate typical output). 101 } 102 fflush(NULL); 103 } 104 } else if (strcmp(argv[1], "UTF-8") == 0) { 105 // test split-up UTF-8 sequence 106 printf("\xc3"); flush_wait(); 107 printf("\xa5\n"); flush_wait(); 108 109 // split up a 2+2 grapheme clusters all possible ways 110 printf("ref: \xc3\xa5\xcc\xb2\n"); flush_wait(); 111 112 printf("1: \xc3"); flush_wait(); 113 printf("\xa5\xcc\xb2\n"); flush_wait(); 114 115 printf("2: \xc3\xa5"); flush_wait(); 116 printf("\xcc\xb2\n"); flush_wait(); 117 118 printf("3: \xc3\xa5\xcc"); flush_wait(); 119 printf("\xb2\n"); flush_wait(); 120 } else if (strcmp(argv[1], "INTERACT") == 0) { 121 char input[256]; 122 char cmd[100]; 123 int arg; 124 125 while (true) { 126 fprintf(stderr, "interact $ "); 127 128 if (fgets(input, sizeof(input), stdin) == NULL) { 129 break; // EOF 130 } 131 132 if (1 == sscanf(input, "%99s %d", cmd, &arg)) { 133 arg = 0; 134 } 135 if (strcmp(cmd, "exit") == 0) { 136 return arg; 137 } else { 138 fprintf(stderr, "command not found: %s\n", cmd); 139 } 140 } 141 } else if (strcmp(argv[1], "EXIT") == 0) { 142 int code = 1; 143 if (argc >= 3) { 144 if (sscanf(argv[2], "%d", &code) != 1) { 145 fprintf(stderr, "Invalid exit code: %s\n", argv[2]); 146 return 2; 147 } 148 } 149 return code; 150 } else { 151 fprintf(stderr, "Unknown first argument: %s\n", argv[1]); 152 return 3; 153 } 154 fflush(NULL); 155 return 0; 156 } else if (argc == 1) { 157 fprintf(stderr, "ready $ "); 158 return 0; 159 } else { 160 fprintf(stderr, "Missing first argument\n"); 161 return 2; 162 } 163 }