Skip to content

Commit

Permalink
已支持if流程控制,并修改了错误的sizeof用法
Browse files Browse the repository at this point in the history
  • Loading branch information
thinszx committed Dec 29, 2020
1 parent 28753c4 commit f3fdbbe
Show file tree
Hide file tree
Showing 9 changed files with 276 additions and 12 deletions.
75 changes: 75 additions & 0 deletions controlflow.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* controlflow.c - 用来进行流程控制
*/
#include<stdio.h>
#include<string.h>
#include "winshell.h"

enum states {NEUTRAL, WANT_THEN, THEN_BLOCK}; // 将流程控制分为三个分区
enum results {SUCCESS, FAIL};

static int if_state = NEUTRAL;
static int if_result = SUCCESS;
static int processed_stat = 0; // 流程控制语句中进程执行的状态

// 通过当前的if_state判断是否可以进行语句的执行任务
int execute_check() {
int rv = 0; // 检查结果

if (if_state == WANT_THEN) // if后面本应紧跟then却未出现
rv = syn_err((char*)"then expected"); // rv == -1
else if (if_state == THEN_BLOCK && if_result == FAIL) // 未成功执行条件语句
rv = -1;
// 其余情况或中立区,直接执行命令即可,无需判断
return rv;
}

// 判断是否为流程控制语句
int is_control_command(char* s) {
return (strcmp(s, "if") == 0
|| strcmp(s, "then") == 0
|| strcmp(s, "fi") == 0
);
}

// 根据当前if_state的状态进行条件语句的执行
int do_control_command(char** args) {
char* ctrlflag = args[0];
int rv = -1; // 条件语句执行成功标志,默认为不成功

if (strcmp(ctrlflag, "if") == 0) {
if (if_state != NEUTRAL) // 当前不在中立区当中
rv = syn_err((char*)"if unexpected");
else {
processed_stat = process(args + 1); // 指向流程控制语句后的第一部分
if_result = (processed_stat == 0 ? SUCCESS : FAIL);
if_state = WANT_THEN; // 期望then语句,shell中IF后面必须跟then语句
rv = 0; // 返回成功执行标志
}
}
else if (strcmp(ctrlflag, "then") == 0) {
if (if_state != WANT_THEN) // 当前不在WANT_THEN区域中却出现了then
rv = syn_err((char*)"then unexpected");
else {
if_state = THEN_BLOCK;
rv = 0;
}
}
else if (strcmp(ctrlflag, "fi") == 0) {
if (if_state != THEN_BLOCK)
rv = syn_err((char*)"fi unexpected");
else {
if_state = NEUTRAL;
rv = 0;
}
}
else
fatal((char*)"internal error processing: ", ctrlflag, 2);
return rv;
}

int syn_err(char* msg) {
if_state = NEUTRAL;
fprintf_s(stderr, "syntax error: %s\n", msg);
return -1;
}
24 changes: 16 additions & 8 deletions exec1.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
#include <stdio.h>
#include <Windows.h>

#define DEBUG

int main()

/*
Expand All @@ -31,7 +29,8 @@ DWORD WaitForSingleObject(
#ifdef DEBUG
// 打开文件
FILE* fp;
errno_t err = fopen_s(&fp, "C:\\Users\\12176\\Desktop\\操作系统课设\\winshell\\test.sh", "r");
// errno_t err = fopen_s(&fp, "C:\\Users\\12176\\Desktop\\操作系统课设\\winshell\\test.sh", "r");
errno_t err = fopen_s(&fp, "C:\\Users\\12176\\Desktop\\操作系统课设\\winshell\\iftest.sh", "r");
if (fp == NULL || err != 0) {
printf_s("Failed to open file!");
return -1;
Expand All @@ -44,7 +43,9 @@ DWORD WaitForSingleObject(
break;
if (*buf == '\0') // 空行的情况
continue;

char** args = splitline(buf);
process(args);
/* 方便起见,这一部分在process.c中封装成了函数供其他程序调用
wchar_t* arg = generate_cmd(buf);
STARTUPINFO si = { sizeof(si) };
Expand All @@ -58,6 +59,13 @@ DWORD WaitForSingleObject(
// 等待进程结束,等待时间为永久
DWORD status = WaitForSingleObject(pi.hProcess, INFINITE);
// 检查进程结束的状态码
DWORD dwErr;
GetExitCodeProcess(pi.hProcess, &dwErr);
if (dwErr)
printf("Failed to execute command, exit code %d\n", dwErr);
// printf_s("Exit code: %d\n", dwErr); // 错误时输出为1
if (status == WAIT_OBJECT_0) {
printf("PID = %d is closed!\n\n", pi.dwProcessId);
}
Expand All @@ -68,15 +76,15 @@ DWORD WaitForSingleObject(
}
else {
printf("Application NOT running! \t Error code %d", GetLastError());
}
}*/
/*
char** args = splitline(buf);
for (int i = 0; args[i] != NULL; i++) {
printf_s("arg[%d]%s\n", i, args[i]);
}
//printf_s("arg[%d]%s\n", i, args[i]);
freelist(args);*/
}/*
}/* 这部分本来就没用
for (int i = 0; args[i] != NULL; i++) {
printf_s("arg[%d]%s\n", i, args[i]);
}*/
Expand Down Expand Up @@ -123,10 +131,10 @@ wchar_t* generate_cmd(char* str) {
size_t converted = 0;
wchar_t* cmdstr = char2wchar(str, &converted);
wchar_t* cmdall = malloc_s((3 + converted) * sizeof(wchar_t));
memset(cmdall, 0, sizeof(cmdall));
memset(cmdall, 0, (3 + converted) * sizeof(wchar_t));
errno_t err = 0;
//wchar_t* cmdall = L"/C ";
err = wcscat_s(cmdall, 3+converted, L"/C ");
err = wcscat_s(cmdall, 3 + converted, L"/C ");
err = wcscat_s(cmdall, 3 + converted, cmdstr);
if (err != 0) {
printf_s("Failed to generate command line!");
Expand Down
3 changes: 3 additions & 0 deletions iftest.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
if echo if success
then
echo then success
143 changes: 143 additions & 0 deletions process.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* 进程执行
*/
#include <Windows.h>
#include "winshell.h"

DWORD process(char** args) {
int rv = 0;
if (args[0] == NULL)
rv = 0;
else if (is_control_command(args[0]))
rv = do_control_command(args);
else if (execute_check() == 0)
rv = execute(args);
return rv;
}


/* 执行命令,返回值为执行结果
* 1. 首先需要将命令的char**数组转换为拼接成一整个char*字符串
* {"echo", "this"} -> "echo this" ----- combine_char()
* 2. 将char*转换为wchar_t*,并在上一步得到的字符串前加上L"/C "
* /C 是cmd的一个参数 -------------------- generate_cmd()
* 3. 调用cmd执行命令,并输出进程的起始、结束,失败时提示退出进程的exit code错误
*/
DWORD execute(char** args) {
char* buf = concatenate_char_array(args); // 存储args拼接起来的字符串
// printf_s("%s\n", buf);

wchar_t cmd[] = L"C:\\Windows\\System32\\cmd.exe";
wchar_t* arg = generate_cmd(buf);
STARTUPINFO si = { sizeof(si) };

PROCESS_INFORMATION pi;
BOOL OK = CreateProcessW(cmd, arg, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); // 运行有参数命令
//BOOL OK = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); // 运行无参数命令,这行只是为了做笔记,其实这个程序根本用不到
// 检查进程结束的状态码
DWORD dwErr = 0;
if (OK) { // 进程创建成功
printf("Applicaiton is running\n");
printf("PID = %d\n", pi.dwProcessId);

// 等待进程结束,等待时间为永久
DWORD status = WaitForSingleObject(pi.hProcess, INFINITE);

GetExitCodeProcess(pi.hProcess, &dwErr);
if (dwErr)
printf("Failed to execute command, exit code %d\n", dwErr);
// printf_s("Exit code: %d\n", dwErr); // 错误时输出为1

if (status == WAIT_OBJECT_0) {
printf("PID = %d is closed!\n\n", pi.dwProcessId);
}
free(buf);
free(arg);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
else {
printf("Application NOT running! \t Error code %d", GetLastError());
}
/*
char** args = splitline(buf);
for (int i = 0; args[i] != NULL; i++) {
printf_s("arg[%d]%s\n", i, args[i]);
}
//printf_s("arg[%d]%s\n", i, args[i]);
freelist(args);*/

return dwErr;
}

// 连接多个字符串
// 由于预先不知道字符串长度,这里没有用strcat,而是用了strcpy+缓冲池长度翻倍进行了拼接
// strcat要求对缓冲区进行初始化,但拼接到一半时,缓冲区时有值的,而如果只初始化未分配的地方会很耗时间
// 所以干脆预定义缓冲池大小,不够了再翻倍,每次翻倍直接把之前的缓冲区strcpy到新缓冲区中,然后再free之前缓冲区
/*
char* concatenate_char_array(char** arr) {
char** posarray = arr;
char* buf = (char*)malloc_s(sizeof(char));
int bufsize = 0;
int arraysize = 0; // 当前指向的char*的大小
int pos = 0;
while (posarray != NULL) {
arraysize = strlen(*posarray) * sizeof(char);
if (pos + arraysize >= bufsize) { // 不用+1给\0分配空间,因为sizeof包含\0
if (bufsize == 0) { // 当目前尚未有任何空间时,默认分配一个BUFSIZ,默认为512
buf = (char*)realloc_s(buf, BUFSIZ);
// memset(buf, 0, sizeof(buf)); // 初始化缓冲区,否则调用strcat_s会报错
}
else {
buf = (char*)(realloc_s(buf, (bufsize + BUFSIZ)));
}
bufsize += BUFSIZ; // 更新缓冲区大小
}
#pragma warning(suppress : 4996)
strncat_s(buf, *posarray);
posarray++;
}
return buf;
}
*/

char* concatenate_char_array(char** arr) {
char** posarray = arr;
char* buf = (char*)malloc_s(sizeof(char));
int bufsize = 0;
int arraysize = 0; // 当前指向的char*的大小
int pos = 0; // 现在已经用了多少缓冲区内存
while (*posarray != NULL) {
char* arg = *posarray;
// 在非第一个参数之前加一个空格
if (pos == 0) // 第一个参数,前面不用加空格
arraysize = strlen(arg) * sizeof(char);
else {
arraysize = strlen(arg) * sizeof(char) + 2; // 这里+1是为了给语句前的空格分配空间
char* tmp = (char*)malloc_s(arraysize);
sprintf_s(tmp, arraysize, "%c%s", ' ', arg);
arg = tmp;
}

if (pos + arraysize >= bufsize) { // 不用+1给\0分配空间,因为sizeof包含\0
if (bufsize == 0) { // 当目前尚未有任何空间时,默认分配一个BUFSIZ,默认为512
buf = (char*)realloc_s(buf, BUFSIZ);
memset(buf, 0, BUFSIZ); // 初始化缓冲区,否则调用strcat_s会报错
}
else {
char* newbuf = (char*)(malloc_s(bufsize + BUFSIZ));
memset(newbuf, 0, bufsize + BUFSIZ);
// memmove_s(newbuf, bufsize + BUFSIZ, buf, bufsize);
strcpy_s(newbuf, bufsize, buf);
free(buf); // 释放之前的内存
buf = newbuf;
}
bufsize += BUFSIZ; // 更新缓冲区大小
}

pos += arraysize;
strcat_s(buf, bufsize, arg);
posarray++;
}
return buf;
}
5 changes: 5 additions & 0 deletions splitline.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,9 @@ void* realloc_s(void* p, size_t n) {
FatalExit(1);
}
return rv;
}

void fatal(char* s1, char* s2, int n) {
//fprintf_s(stderr, "Error: %s, %s\n", s1, s2);
//exit(n);
}
2 changes: 2 additions & 0 deletions test.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
echo success in print; echo success in split line by \;

echo success in change line;

ehco 11
18 changes: 17 additions & 1 deletion winshell.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
#pragma once
#include<stdio.h>
#include<Windows.h>

#define DEBUG

/* 定义在splitline.c中 */
char* readline(FILE* fp);
char** splitline(char* line);
char* createstr(char* s, int l);
void* malloc_s(size_t n);
void* realloc_s(void* p, size_t n);
void fatal(char* s1, char* s2, int n);

/* 定义在exec.c中 */
wchar_t* char2wchar(char* text, size_t* converted);
wchar_t* generate_cmd(char* str);
wchar_t* generate_cmd(char* str);

/* 定义在controlflow.c中,用作流程控制 */
int execute_check();
int is_control_command(char* s);
int do_control_command(char** args);
int syn_err(char* msg);

/* 定义在process.c中,用作进程执行 */
DWORD process(char** args);
DWORD execute(char** args);
char* concatenate_char_array(char** arr);
3 changes: 3 additions & 0 deletions winshell.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="exec1.c" />
<ClCompile Include="controlflow.c" />
<ClCompile Include="process.c" />
<ClCompile Include="splitline.c" />
<ClCompile Include="没用的api啥的.c" />
</ItemGroup>
Expand All @@ -149,6 +151,7 @@
<ClInclude Include="winshell.h" />
</ItemGroup>
<ItemGroup>
<None Include="iftest.sh" />
<None Include="test.sh" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
Expand Down
Loading

0 comments on commit f3fdbbe

Please sign in to comment.