我为自己的作业编写了一个程序,但是我犯了一个错误并设置为 由于该结构限制,该程序可以使用的用户数不变。我试着做一些realloc来扩展结构但它没有用,我得到了:
gcc:错误:O"SxW��D(/��A>A�0:没有这样的文件或目录
gcc:致命错误:没有输入文件
编译终止。
这是我的代码与相关行附近的待办事项,我将非常感谢一种方法,这将帮助我使代码与用户数量相关的不那么严格。谢谢!
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <dirent.h>
#include <memory.h>
#include <unistd.h>
#include <wait.h>
#define MAX_LENGTH 160
#define STDERR_FILDES 2
#define OPERATION_FAILED (-1)
#define BUFFER_SIZE 512
#define CONFIG_PLACE 1
#define CORRECT_ARGS_NUM 2
#define WRONG_ARGS_NUM_MSG "Wrong number of program arguments. Please enter 2 arguments."
#define SPACE_CHAR ' '
#define NEW_LINE_CHAR '\n'
#define NULL_CHAR '\0'
#define NULL_STR "\0"
#define SLASH_CHAR '/'
#define SLASH_STR "/"
#define CURR_DIR "."
#define PAR_DIR ".."
#define C_EXTENT "c"
#define EXT_DOT '.'
#define NUM_OF_USERS 5 //todo: here I define the rigid number of users.
#define ZERO_SCORE "0"
#define SON 0
#define NO_FILE "NO_C_FILE"
#define TIMEOUT "TIMEOUT"
#define COMP_ERR "COMPILATION_ERROR"
#define SIXTY_SCORE "60"
#define BAD_OUT "BAD_OUTPUT"
#define EIGHTY_SCORE "80"
#define SIM_OUT "SIMILAR_OUTPUT"
#define HUNDRED_SCORE "100"
#define GREAT_OUT "GREAT_JOB"
#define EQUAL 0
#define EXE_FILE_NAME "temp.out"
#define RUN_FILE_NAME "./temp.out"
#define COMP_FILE_NAME "./comp.out"
#define RES_FILE_NAME "res.txt"
#define OPER "gcc"
#define OPT_FLAG "-o"
#define RESULTS_FILE_REL_PATH "results.csv"
#define RESULTS_FILE_PERMISSIONS 0644
#define CSV_LINE_MAX_LEN 500
#define CSV_SEPARATOR ","
#define CSV_END_LINE "\n"
#define SECONDS_TO_SLEEP 5
#define WAIT_FOR_ANY_CHILD 0
#define IDENTICAL 3
#define SIMILAR 2
#define DIFFERENT 1
enum Bool
{
false = 0,
true = 1
};
typedef struct User {
char name[MAX_LENGTH];
char filePath[MAX_LENGTH];
char dirPath[MAX_LENGTH];
char score[MAX_LENGTH];
char scoreInfo[MAX_LENGTH];
} User;
/**
* Prints an error message using write function to file descriptor
* number 2 (stderr), and exits with error status -1 (translates to 255).
*/
void sysCallFailureProcedure() {
char errorMsg[] = "Error in system call\n";
write(STDERR_FILDES, errorMsg, sizeof(errorMsg)-1);
exit(OPERATION_FAILED);
}
/**
* Get the file's extension.
* @param filename The filename.
* @return The file's extension.
*/
char *getFilenameExt(char *filename) {
char *dot = strrchr(filename, EXT_DOT);
if(!dot || dot == filename) return "";
return dot + 1;
}
/**
* Get the configurations from the configurations file.
* @param configfilePath The configurations file.
* @param mainDirPath The main directory path.
* @param inputFilePath The input file path.
* @param correctResFilePath The correct result file path.
*/
void getConfigFromFile(char* mainDirPath, char* inputFilePath, char* correctResFilePath, char* configfilePath){
int configFileDes = open(configfilePath, O_RDONLY);
if (configFileDes < 0){
sysCallFailureProcedure();
}
int retVal;
char buff[BUFFER_SIZE];
while ((retVal = read(configFileDes, buff, sizeof(buff))) > 0){
int lineNumber = 1;
int lineIdx = 0;
int i=0;
for (; i<retVal; i++) {
if (lineNumber == 1){
if (buff[i] == NEW_LINE_CHAR || buff[i] == SPACE_CHAR || buff[i] == NULL_CHAR) {
lineNumber = 2;
lineIdx = 0;
} else {
mainDirPath[lineIdx] = buff[i];
lineIdx++;
}
}
else if (lineNumber == 2){
if (buff[i] == NEW_LINE_CHAR || buff[i] == SPACE_CHAR || buff[i] == NULL_CHAR) {
lineNumber = 3;
lineIdx = 0;
} else {
inputFilePath[lineIdx] = buff[i];
lineIdx++;
}
}
else if (lineNumber == 3){
if (buff[i] != NEW_LINE_CHAR && buff[i] != SPACE_CHAR && buff[i] != NULL_CHAR) {
correctResFilePath[lineIdx] = buff[i];
lineIdx++;
}
}
}
}
if (retVal < 0){
sysCallFailureProcedure();
}
if (close(configFileDes) < 0){
sysCallFailureProcedure();
}
}
/**
* Get the C file.
* @param user The user.
* @param userNum The user Num.
* @param directory The directory.
* @param filePath The file path.
*/
void getCFile(User* user, int userNum, char* directory,char* filePath){
DIR* pDir = opendir(directory);
if (pDir == NULL){
sysCallFailureProcedure();
}
struct dirent* pDirent;
while((pDirent = readdir(pDir))!=NULL) {
if ((pDirent->d_type == DT_DIR) && (strcmp(pDirent->d_name, CURR_DIR) != 0)
&& (strcmp(pDirent->d_name, PAR_DIR) != 0)){
char dir[MAX_LENGTH]={};
strcpy(dir,directory);
int length = strlen(dir);
if (dir[length] != SLASH_CHAR) {
strcat(dir, SLASH_STR);
}
strcat(dir, pDirent->d_name);
getCFile(user, userNum, dir, filePath);
} else if (pDirent->d_type == DT_REG) {
char* extension = getFilenameExt(pDirent->d_name);
if(strcmp(extension,C_EXTENT) == 0) {
strcpy(filePath, pDirent->d_name);
strcpy(user[userNum].dirPath, directory);
break;
}
}
}
}
/**
* Process the main directory.
* @param users The users.
* @param userNum The user num.
* @param mainDirPath The main directory path.
*/
void processMainDir(User* users, int* userNum, char* mainDirPath){
DIR* pDir = opendir(mainDirPath);
if (pDir == NULL){
sysCallFailureProcedure();
}
struct dirent* pDirent;
int usersSize = NUM_OF_USERS; // todo: remove if may...
int userSize = sizeof(struct User);
while ((pDirent = readdir(pDir))!=NULL) {
if ((pDirent->d_type == DT_DIR) && (strcmp(pDirent->d_name, CURR_DIR) != 0)
&& (strcmp(pDirent->d_name, PAR_DIR) != 0)){
strcpy(users[*userNum].name, pDirent->d_name);
char path[MAX_LENGTH] = {};
char dir[MAX_LENGTH]={};
strcpy(dir, mainDirPath);
int length = strlen(dir);
if (dir[length] != SLASH_CHAR) {
strcat(dir, SLASH_STR);
}
strcat(dir, pDirent->d_name);
getCFile(users, *userNum, dir, path);
strcpy(users[*userNum].filePath, path);
(*userNum)++;
if ((*userNum) >= usersSize){
usersSize += NUM_OF_USERS;
users = (User*) realloc(users, usersSize * userSize); // todo: check it out. it doesn't work!
if (users == NULL){
sysCallFailureProcedure();
}
}
}
}
if (closedir(pDir) == OPERATION_FAILED){
sysCallFailureProcedure();
}
}
/*
* Return true if there is an executable file.
*/
enum Bool isThereExecutable(){
char workingDir[BUFFER_SIZE];
DIR* pDir;
struct dirent* pDirent;
getcwd(workingDir, sizeof(workingDir));
if ((pDir = opendir(workingDir)) == NULL){
sysCallFailureProcedure();
}
while ((pDirent = readdir(pDir)) != NULL){
if (strcmp(pDirent->d_name, EXE_FILE_NAME) == EQUAL){
return true;
}
}
return false;
}
/**
* Fill up the results file.
* @param resultsFilePath The path to the results file.
* @param userNum The number of users.
* @param users The users struct.
*/
void fillTheResultsFile(char* resultsFilePath, int userNum, User* users){
int resultsFileDes = open(resultsFilePath, O_WRONLY | O_CREAT | O_TRUNC, RESULTS_FILE_PERMISSIONS);
if (resultsFileDes < 0){
sysCallFailureProcedure();
}
int i;
for (i=0; i<userNum; i++) {
char line[CSV_LINE_MAX_LEN] = {};
strcpy(line, users[i].name);
strcat(line, CSV_SEPARATOR);
strcat(line, users[i].score);
strcat(line, CSV_SEPARATOR);
strcat(line, users[i].scoreInfo);
if (i < userNum -1){
strcat(line, CSV_END_LINE);
}
if (write(resultsFileDes, line, sizeof(line)-1) < 0){
sysCallFailureProcedure();
}
}
if (close(resultsFileDes) < 0){
sysCallFailureProcedure();
}
}
/**
* Execute a file.
* @param argv The file's args.
*/
void executeFile(char* argv[]){
pid_t pId = fork();
if (pId == SON) {
int retVal = execvp(argv[0], &argv[0]);
if (retVal == OPERATION_FAILED) {
sysCallFailureProcedure();
}
}else{
waitpid(pId, NULL, WCONTINUED);
}
}
void executeProg(User* users, int userNum, char* inputFilePath, char* correctResFilePath){
char* runArgs[] = {RUN_FILE_NAME, NULL};
int status;
pid_t pId = fork();
if (pId == SON){
int inputFileFileDes = open(inputFilePath, O_RDONLY);
if (inputFileFileDes < 0){
sysCallFailureProcedure();
}
int resFileFileDes = open(RES_FILE_NAME, O_WRONLY | O_CREAT | O_TRUNC, RESULTS_FILE_PERMISSIONS);
if (resFileFileDes < 0){
sysCallFailureProcedure();
}
if (dup2(inputFileFileDes, STDIN_FILENO) < 0){
sysCallFailureProcedure();
}
if (dup2(resFileFileDes, STDOUT_FILENO) < 0){
sysCallFailureProcedure();
}
if (execvp(runArgs[0], &runArgs[0]) < 0){
sysCallFailureProcedure();
}
if (close(inputFileFileDes) < 0){
sysCallFailureProcedure();
}
if (close(resFileFileDes) < 0){
sysCallFailureProcedure();
}
} else {
sleep(SECONDS_TO_SLEEP);
if (waitpid(pId, &status, WNOHANG) == 0){
strcpy(users[userNum].scoreInfo, TIMEOUT);
strcpy(users[userNum].score, ZERO_SCORE);
} else {
char* copmArguments[] = {COMP_FILE_NAME , RES_FILE_NAME, correctResFilePath, NULL};
pid_t pId2 = fork();
if (pId2 == SON){
if (execvp(copmArguments[0], &copmArguments[0]) < 0){
sysCallFailureProcedure();
}
} else{
waitpid(pId2, &status, WAIT_FOR_ANY_CHILD);
if (WIFEXITED(status)){
int compRes = WEXITSTATUS(status);
if (compRes == IDENTICAL){
strcpy(users[userNum].scoreInfo, GREAT_OUT);
strcpy(users[userNum].score, HUNDRED_SCORE);
} else if (compRes == SIMILAR){
strcpy(users[userNum].scoreInfo, SIM_OUT);
strcpy(users[userNum].score, EIGHTY_SCORE);
} else if (compRes == DIFFERENT){
strcpy(users[userNum].scoreInfo, BAD_OUT);
strcpy(users[userNum].score, SIXTY_SCORE);
}
}
if (unlink(EXE_FILE_NAME) < 0){
sysCallFailureProcedure();
}
if (unlink(RES_FILE_NAME) < 0){
sysCallFailureProcedure();
}
}
}
}
}
/**
* Get the scores and score info's.
* @param inputFilePath The input file path.
* @param correctResFilePath The correct result file path.
* @param users The users.
* @param userNum The user num.
*/
void getScoresAndInfo(char* inputFilePath, char* correctResFilePath, User* users, int userNum){
int i;
for (i=0; i<userNum; i++) {
if (strcmp(NULL_STR, users[i].filePath) == EQUAL){
strcpy(users[i].scoreInfo, NO_FILE);
strcpy(users[i].score, ZERO_SCORE);
} else {
char CompletePathToFile[MAX_LENGTH] = {};
strcpy(CompletePathToFile, users[i].dirPath);
strcat(CompletePathToFile, SLASH_STR);
strcat(CompletePathToFile, users[i].filePath);
char* executeArguments[] = {OPER, OPT_FLAG, EXE_FILE_NAME, CompletePathToFile, NULL};
executeFile(executeArguments);
if (!isThereExecutable()){
strcpy(users[i].scoreInfo, COMP_ERR);
strcpy(users[i].score, ZERO_SCORE);
} else {
executeProg(users, i, inputFilePath, correctResFilePath);
}
}
}
}
int main(int argc, char *argv[]) {
if (argc != CORRECT_ARGS_NUM) {
printf(WRONG_ARGS_NUM_MSG);
exit(OPERATION_FAILED);
}
char mainDirPath[MAX_LENGTH] = {};
char inputFilePath[MAX_LENGTH] = {};
char correctResFilePath[MAX_LENGTH] = {};
getConfigFromFile(mainDirPath, inputFilePath,correctResFilePath, argv[CONFIG_PLACE]);
User* users = (User*)malloc(sizeof(User) * NUM_OF_USERS); // todo: here I malloc the users struct
int idx = 0;
if (users == NULL){
sysCallFailureProcedure();
}
processMainDir(users, &idx, mainDirPath);
getScoresAndInfo(inputFilePath, correctResFilePath, users, idx);
fillTheResultsFile(RESULTS_FILE_REL_PATH, idx, users);
}