Related
iv tried a lot of solutions to try to get this working (i.e using memcpy etc) I cant seem to find the issue, depending on what I try I either end up with gibberish or SEGV
iv spent a lot of time already googling and trying different ways, i still cant figure out why the arrays won't combine successfully
#include <stdio.h>
#include <stdint.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
#define log_info printf
typedef struct
{
char* name;
//size_t size;
} entry_t;
/* qsort struct comparison function (C-string field) */
static int struct_cmp_by_name(const void* a, const void* b)
{
entry_t* ia = (entry_t*)a;
entry_t* ib = (entry_t*)b;
return strcmp(ia->name, ib->name);
/* strcmp functions works exactly as expected from comparison function */
}
entry_t* get_item_entries(const char* dirpath, int* count)
{
struct dirent* dent;
char buffer[512]; // fixed buffer
int dfd = 0,
n, r = 1; // item counter, rounds to loop
entry_t* p = NULL; // we fill this struct with items
loop:
n = 0;
printf("loop: %d, count:%d\n", r, *count);
// try to open dir
dfd = open(dirpath, O_RDONLY, 0);
if (dfd < 0)
{
printf("Invalid directory. (%s)\n", dirpath);
*count = -1;
return NULL;
}
else
{
printf("open(%s)\n", dirpath);
}
memset(buffer, 0, sizeof(buffer));
while (syscall(SYS_getdents, dfd, buffer, sizeof(buffer)) != 0)
{
dent = (struct dirent*)buffer;
while (dent->d_fileno)
{ // skip `.` and `..`
if (!strncmp(dent->d_name, "..", 2)
|| !strncmp(dent->d_name, ".", 1)) goto skip_dent;
// deal with filtering outside of this function, we just skip .., .
switch (r)
{ // first round: just count items
case 1:
{
// skip special cases
if (dent->d_fileno == 0) goto skip_dent;
break;
}
// second round: store filenames
case 0: p[n].name = strdup(dent->d_name); break;
}
n++;
skip_dent:
dent = (struct dirent*)((void*)dent + dent->d_reclen);
if (dent == (void*)&buffer[512]) break; // refill buffer
}
memset(buffer, 0, sizeof(buffer));
}
close(dfd);
// on first round, calloc for our list
if (!p)
{ // now n holds total item count, note it
p = calloc(n, sizeof(entry_t));
*count = n;
}
// first round passed, loop
r--; if (!r) goto loop;
// report count
printf("%d items at %p, from 1-%d\n", *count, (void*)p, *count);
/* resort using custom comparision function */
qsort(p, *count, sizeof(entry_t), struct_cmp_by_name);
// report items
//for (int i = 0; i < num; ++i) log_error( "%s", p[i].name);
return p;
}
int main(int argc, char* argv[])
{
int HDD_count = -1;
uint32_t total = -1;
int ext_count = -1;
entry_t* e = NULL;
entry_t *HDD = get_item_entries("/mnt/f/n", &HDD_count);
entry_t* ext = get_item_entries("/mnt/f/dls", &ext_count);
total = ext_count + HDD_count;
e = (entry_t*)malloc(sizeof *e * total);
if (e != NULL)
{
for (int i = 1; i < HDD_count; i++)
{
log_info("HDD[%i].name %s\n", i, HDD[i].name);
e[i].name = strdup(HDD[i].name);
}
for (int i = 1; i < ext_count; i++)
{
log_info("ext[%i].name %s\n", i, ext[i].name);
e[i + HDD_count].name = strdup(ext[i].name);
}
}
else
printf("Failed to Allocate the Array");
char tmp[256];
int i = 1, j;
for(j = 1; j <= total; j++)
{
snprintf(&tmp[0], 255, "%s", e[ j].name);
log_info("%i:%s\n", j , tmp);
}
return 0;
}
Here is a rewrite of a snippet of main() that I mentioned in my comment above:
#define CHECK(p, msg) if(!(p)) { printf("%s:%d: %s", __FILE__, __LINE__, msg); return 1;}
...
entry_t *HDD = get_item_entries("/mnt/f/n", &HDD_count);
CHECK(HDD, "HDD failed to get entries");
entry_t *ext = get_item_entries("/mnt/f/dls", &ext_count);
CHECK(ext, "ext failed to get entries");
uint32_t total = HDD_count + ext_count;
entry_t *e = malloc(total * sizeof(*e));
CHECK(e, "malloc failed");
for(int i = 0; i < HDD_count; i++) {
log_info("HDD[%i].name %s\n", i, HDD[i].name);
e[i].name = strdup(HDD[i].name);
}
// write a function instead of duplicating code?
for (int i = 0; i < ext_count; i++) {
log_info("ext[%i].name %s\n", i, ext[i].name);
e[HDD_count + i].name = strdup(ext[i].name);
}
It looks like a short lived program, but I would still free the values from strdup() and e itself.
so i am having an issue i do not know how to fix... basically the lexer has one main function: tokenize() (idk if the spelling is even correct). Anyways, at line 50 i am calling malloc to allocate some memory for the tokens which are going to get generated, the size being:
scriptsize * sizeof(struct token). but when i try to allocate more than 10 tokens: the program crashes with malloc(): corrupted top size, can you guys help me? thanks and have a good day.
lexer.c
// low level token types: used in early parsing, and tokenizing of the text
enum llt {separator, operator, number, string, identifier, character, newline};
// string representation of low level token types
char * strllt[] = {"separator", "operator", "number", "string", "identifier", "character", "newline"};
const char separators[] = "({[ \n\t,.)};]";
const char operators[] = "+*&%^/=-";
const char numbers[] = "0123456789.";
const char whitespaces[] = "\n\t ";
struct token {int type; char * value;};
int token_equals(struct token t1, struct token t2)
{
if(t1.type == t2.type & t1.value == t2.value) {return 1;}
return 0;
}
// returns pointer to concatonation of the two selected strings
char * stradd(char * base, char * adder, int size_a, int size_b)
{
char * combined_string = (char *)malloc(size_b);
for(int i=0;i<size_a;i++) {combined_string[i] = base[i];}
for(int i=0;i<size_b;i++) {combined_string[i+size_a] = adder[i];}
return combined_string;
}
// checks if the selected character is in the selected string
int contains(const char * string, char character, int strsize)
{
for(int i=0;i<strsize;i++)
{
if(character == string[i]) {return 1;}
}
return 0;
}
int get_token_type(char character)
{
if(contains(separators, character, sizeof(separators))) {return 0;}
if(contains(operators, character, sizeof(operators))) {return 1;}
if(contains(numbers, character, sizeof(numbers))) {return 2;}
return 4; // could be a string also
}
// generates a token array out of a text, core function of the lexer
struct token * tokenize(char * text, int text_size, int * size_ptr)
{
struct token * tokens = (struct token *)malloc(sizeof(struct token) * text_size);
int tokens_current_index = 0; // next offset for a new token
char * _identifier = 0; // used to generate multi-char tokens
int id_size = 0; // the size of _identifier
int line = 0; // the current line
char * strepr = 0; // string representation of the current line
int line_size = 0; // the size of strepr
for(int i=0;i<text_size;i++)
{
// the token type of the current character
int token_type = get_token_type(text[i]);
// the token is either a separator, or an operator
if(token_type < 2)
{
// the end of an identifier has been detected
if(_identifier != 0 )
{
tokens[tokens_current_index] = (struct token){identifier, _identifier};
_identifier = 0; tokens_current_index++; id_size = 0;
}
// add the newly detected token to the token array, if it is not a whitespace
if(!contains(whitespaces, text[i], sizeof(whitespaces)))
{
tokens[tokens_current_index] = (struct token){token_type, &text[i]};
tokens_current_index++;
}
else if(text[i] == '\n')
{
// add a newline token with value strepr (used in error handling)
tokens[tokens_current_index] = (struct token){newline, strepr};
line_size = 0; strepr = 0; line++; tokens_current_index++;
}
}
if(token_type == identifier)
{
// the character is the first letter in the identifier
if(_identifier == 0)
{
// make the first letter of the identifier the current letter
_identifier = ""; id_size = 1;
_identifier = stradd("", &text[i], 0, 1);
}
// the chatacter is not the first letter in the identifier
else
{
// append the new letter to the currently generating identifier
_identifier = stradd(_identifier, &text[i], id_size, 1);
id_size++;
}
}
if(token_type == number)
{
// the number is part of an identifier: for example a10
if(_identifier != 0)
{
_identifier = stradd(_identifier, &text[i], id_size, 1);
id_size++;
}
// the number is not part of an identifier: for example 100
else
{
int dot_amount = 0; // 1.1.1 causes an error, 1.1 does not
char * str_number = ""; // the number being generated
int num_size = 0; // the lenght of the number being generated
// generate the number token, similar to an identifier generation
for(int x=i;x<text_size;x++)
{
// check if the next letter is a number, if it is not, break
int next_token_type = get_token_type(text[x]);
if(next_token_type == number || text[i] == '.')
{
str_number = stradd(str_number, &text[i], num_size, 1);
if(text[i] == '.') {dot_amount++;} // used in error check
}
else
{
// the dot amount is invalid: for example 1..2
if(dot_amount > 1)
{
printf("syntax error in line %i: in %s\n", line, str_number);
exit(-1);
}
// add the newly generated number token to the token array
tokens[tokens_current_index] = (struct token){number, str_number};
tokens_current_index++; i--; break; // stop generating number
}
// add the current character to the strepr of the line
if(strepr == 0) {strepr = stradd("", &text[i], 0, 1); line_size++;}
else
{
strepr = stradd(strepr, &text[i], line_size, 1);
line_size++;
}
// update position of the lexer, and update num_size
i++; num_size++;
}
}
}
if(strepr == 0) {strepr = stradd("", &text[i], 0, 1); line_size++;}
else if(tokens[tokens_current_index-1].type != number)
{
strepr = stradd(strepr, &text[i], line_size, 1);
line_size++;
}
}
// add identifier to the end of the token array
if(_identifier != 0)
{
tokens[tokens_current_index] = (struct token){identifier, _identifier};
}
*size_ptr = tokens_current_index+1;
return tokens;
}
main.c
#include <stdlib.h>
#include <stdio.h>
#include "lexer.h"
int main()
{
char chars[] = "if(x == 3) {return false;";
int size;
struct token * tokens = tokenize(chars, sizeof(chars), &size);
printf("%i\n", size);
for(int i=0;i<size-1;i++)
{
if(tokens[i].type < 2)
{
printf("token at %i:\t(%s, %c)\n", i, strllt[tokens[i].type], *(tokens[i].value));
}
else
{
printf("token at %i:\t(%s, %s)\n", i, strllt[tokens[i].type], tokens[i].value);
}
}
}
note: the code is inefficient, i know, but i will try to fix this myself later on, since the program does not have to be very efficient right now
I am getting this error when compiling:
browninz.buildrooms.c:191:29: error: expected expression before ‘struct’
AddRandomConnection(struct room RoomA.outboundConnections, struct room RoomB.outboundConnections);
^
browninz.buildrooms.c:191:29: error: too few arguments to function ‘AddRandomConnection’
browninz.buildrooms.c:40:6: note: declared here
void AddRandomConnection(struct room *RoomA, struct room *RoomB)
^
Originally I started with about 20+ errors and I have finally scaled it down to a single error within my AddRandomConnections method, I am trying to compile this code and it keeps throwing an error for this single line. I have been trying for a few hours for different methods to fix the error, but I cannot get it to go away. Can anyone help me figure out why I am getting this error?
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
/*#include <stdbool.h>*/
typedef enum
{
false,
true
} bool;
// Creating the template for each of the rooms via struct
struct room
{
int id;
char* name;
char* type;
int numOutboundConnections;
struct room* outboundConnections[5];
};
// Returns true if all rooms have 3 to 6 outbound connections, false otherwise
int IsGraphFull(struct room *structureRooms)
{
int k = 0;
while (k < 7){
if (sizeof(structureRooms[k].numOutboundConnections) < 3){
return 0;
}
k++;
}
return 1;
}
// Adds a random outbound connection between two rooms
void AddRandomConnection(struct room *RoomA, struct room *RoomB)
{
while(true)
{
RoomA = GetRandomRoom(RoomA);
if (CanAddConnectionFrom(RoomA) == true)
break;
}
do
{
RoomB = GetRandomRoom(RoomB);
}
while(CanAddConnectionFrom(RoomB) == false || IsSameRoom(RoomA, RoomB) == true || ConnectionAlreadyExists(RoomA, RoomB) == true);
ConnectRoom(RoomA, RoomB); // TODO: Add this connection to the real variables,
ConnectRoom(RoomB, RoomA); // because this A and B will be destroyed when this function terminates
}
// Returns a random Room, does NOT validate if connection can be added
int GetRandomRoom(struct room *connections[])
{
// Initializes random number generator
srand(time(0));
// Generate random room
int x = rand() % 7;
return x;
}
// Returns true if a connection can be added from Room x (< 6 outbound connections), false otherwise
int CanAddConnectionFrom(struct room *RoomA)
{
if (sizeof(RoomA->numOutboundConnections) < 6)
{
return 1;
}
else{
return 0;
}
}
// Returns true if a connection from Room x and Room y already exists, false otherwise
int ConnectionAlreadyExists(struct room *RoomA, struct room *RoomB)
{
int myConnections;
int i = 0;
for (i; i <= 6; i++){
if ((RoomA->numOutboundConnections = RoomB->id)){
myConnections = 1;
break;
}
if(myConnections == 1)
{
return 1;
}
else
return 0;
}
}
// Connects Rooms A and B together, does not check if this connection is valid
void ConnectRoom(struct room *RoomA, struct room *RoomB)
{
RoomA->numOutboundConnections = RoomB->id;
}
// Returns true if Rooms x and y are the same Room, false otherwise
int IsSameRoom(struct room *RoomA, struct room *RoomB)
{
if (strcmp(RoomA->name, RoomB->name) == 0){
return 1;
}
return 0;
}
int main(int argc, char* argv[])
{
// Room names
char Forest[] = "Forest";
char Beach[] = "Beach";
char Cliff[] = "Cliff";
char River[] = "River";
char Cave[] = "Cave";
char Mountain[] = "Mountain";
char Cabin[] = "Cabin";
char Castle[] = "Castle";
char Fountain[] = "Fountain";
char Homeria[] = "Homeria";
// Initializing a room array variable to store contents of all room names
char* roomName[] = {Forest, Beach, Cliff, River, Cave, Mountain, Cabin, Castle, Fountain, Homeria};
// Creating the structs of 7 rooms each labeled with a name and type slot
struct room Room1;
Room1.id = 1;
Room1.name = calloc(16, sizeof(char));
Room1.type = calloc(16, sizeof(char));
strcpy(Room1.type, "START_ROOM");
struct room Room2;
Room2.id = 2;
Room2.name = calloc(16, sizeof(char));
Room2.type = calloc(16, sizeof(char));
strcpy(Room2.type, "MID_ROOM");
struct room Room3;
Room3.id = 3;
Room3.name = calloc(16, sizeof(char));
Room3.type = calloc(16, sizeof(char));
strcpy(Room3.type, "MID_ROOM");
struct room Room4;
Room4.id = 4;
Room4.name = calloc(16, sizeof(char));
Room4.type = calloc(16, sizeof(char));
strcpy(Room4.type, "MID_ROOM");
struct room Room5;
Room5.id = 5;
Room5.name = calloc(16, sizeof(char));
Room5.type = calloc(16, sizeof(char));
strcpy(Room5.type, "MID_ROOM");
struct room Room6;
Room6.id = 6;
Room6.name = calloc(16, sizeof(char));
Room6.type = calloc(16, sizeof(char));
strcpy(Room6.type, "MID_ROOM");
struct room Room7;
Room7.id = 10;
Room7.name = calloc(16, sizeof(char));
Room7.type = calloc(16, sizeof(char));
strcpy(Room7.type, "END_ROOM");
// Randomizing the room names to append to a random room #
srand(time(0));
struct room structureRooms[7] = {Room1, Room2, Room3, Room4, Room5, Room6, Room7};
int i = 0;
int array1[] = {0 ,0, 0, 0, 0, 0, 0, 0, 0, 0};
// Loop for each of the rooms which checks to see if a name is available, if so, apply to random room
while ( i < 7 ){
int randNum = rand() % 10;
if (array1[randNum] == 0){
array1[randNum] = 1;
strcpy(structureRooms[i].name, roomName[randNum]);
i++;
}
}
// Create all connections in the graph
while (IsGraphFull(structureRooms) == false)
{
AddRandomConnection(struct room RoomA.outboundConnections, struct room RoomB.outboundConnections);
}
// Assigning char limits
char dirname[100];
char dir0[100];
char dir1[100];
char dir2[100];
char dir3[100];
char dir4[100];
char dir5[100];
char dir6[100];
// Generate the "rooms" directory name with the PID
sprintf(dirname, "./browninz.rooms%d", getpid());
// Generate the room names concatenated with the directory name
sprintf(dir0, "%s/Room1", dirname);
sprintf(dir1, "%s/Room2", dirname);
sprintf(dir2, "%s/Room3", dirname);
sprintf(dir3, "%s/Room4", dirname);
sprintf(dir4, "%s/Room5", dirname);
sprintf(dir5, "%s/Room6", dirname);
sprintf(dir6, "%s/Room7", dirname);
// Create a new directory that the "rooms" files will be stored in
mkdir(dirname, 0770);
// Pointer files of each of the rooms
FILE *myRoom1;
FILE *myRoom2;
FILE *myRoom3;
FILE *myRoom4;
FILE *myRoom5;
FILE *myRoom6;
FILE *myRoom7;
// Now opening the room files / directories to create or write them in the folder.
myRoom1 = fopen(dir0, "w+");
myRoom2 = fopen(dir1, "w+");
myRoom3 = fopen(dir2, "w+");
myRoom4 = fopen(dir3, "w+");
myRoom5 = fopen(dir4, "w+");
myRoom6 = fopen(dir5, "w+");
myRoom7 = fopen(dir6, "w+");
// Creating a pointer array of all of the room pointers
FILE *myRooms[7] = {myRoom1, myRoom2, myRoom3, myRoom4, myRoom5, myRoom6, myRoom7};
// Printing room file name, type, and connections and iterates for each room
int counter = 0;
while (counter < 7) {
fprintf(myRooms[counter], "ROOM NAME: %s\n", structureRooms[counter].name);
fprintf(myRooms[counter], "ROOM TYPE: %s\n", structureRooms[counter].type);
// fprintf(myRooms[counter], "CONNECTION 1: %s\n", structureRooms[counter].outboundConnections[counter]);
// test to see if connection works
fprintf(myRooms[counter], "CONNECTION 1: %s\n", structureRooms[counter].name);
counter++;
}
return 0;
}
In your call below, remove the "struct room". You've already declared the type in the function declaration.
// Create all connections in the graph
while (IsGraphFull(structureRooms) == false)
{
AddRandomConnection(struct room RoomA.outboundConnections, struct room RoomB.outboundConnections);
}
So that it is just AddRandommConnection(RoomA.outboundConnections, Roomb.outboundConnections);
I have difficulty in dealing with access to structure members inside a function, and structure instancies are double pointer arguments. I am using strcpy and strcmp and it seems, to me (I used debuger), to do the bad things.
First, I have created structure using typedef, instanciated it 2 times and allocated memory for one of them.
Second, I have created function loadVariablesToMemory to which I am passing instanciated structure instancies as double pointers (2nd row - after //Functions comment).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
//FUNCTIONS
int loadVariablesToMemory(const char* fileName, const char* fileAccessMode, varData **dynamicData, varData **tmp);
//DECLARATION
typedef unsigned short int UINT16;
typedef struct data {
char varName[10];
UINT16 value;
} varData;
int main(){
//ALLOCATING MEMORY
varData *dynamicData;
dynamicData = (varData*)malloc(sizeof(varData));
varData *tmp;
tmp = NULL;
int numOfVars = loadVariablesToMemory("u02v1_input_03.txt", "r", &dynamicData, &tmp);
return 0;
}
Problem:
Inside the function loadVariablesToMemory I am trying to access allocated "variables" of structure instantiated and declared above, using:
.....
if(strcmp((*(dynamicalData+j-1))->varName, buffer) == 0){
.....etc.
strcpy((*(dynamicalData+numOfVars-1))->varName, buffer);
.....etc.
I run the debugger and all seems to work [also If I rewrite entire function outside into Main it works (with little changes with double pointers now single pointers)] but I got stuck in the rows where I use strcpy(); and strcmp() functions and I dont know why and I am little bit desperate, because these two semms to be only two things that prevent me from creating a working function and I am getting desperate as I am dealing with this problem almost 10 hours without any real progress.
COMPLETE FUNCTION loadVariablesToMemoryDECLARATION:
int loadVariablesToMemory(const char* fileName, const char* fileAccessMode, varData **dynamicalData, varData **tmpal) {
FILE *fSource = fopen(fileName, fileAccessMode);
char oneChar = '\0';
char buffer[10];
memset(buffer,'\0',10); //inicialization of buffer chars to \0
int i = 0;
int varOrNum = 0;
int numOfVars = 0;
bool match = false;
while (!feof(fSource)) {
oneChar = fgetc(fSource); //Load letter in file
if((oneChar == ' ') | (oneChar == '\n')) {
i = 0;
if((strcmp(buffer,"NOT") == 0) || (strcmp(buffer,"AND") == 0) || (strcmp(buffer,"OR") == 0) || (strcmp(buffer,"LSHIFT") == 0) || (strcmp(buffer,"RSHIFT") == 0) || (strcmp(buffer,"->") == 0)) {
memset(buffer,'\0',10);
}
else{
varOrNum = atoi(buffer); //returns (0) if varOrNum is variable (0)
if((varOrNum == 0) & (buffer[0] != '0'))
{ //if varOrNum is a variable (0)
for(int j = 0; j<=numOfVars; j++) { //control in memory for match of variable name
//HERE SEEMS NOT TO WORK - this is just random try if strcpy will work
//strcpy((*(dynamicalData+j-1))->varName, buffer);
//HERE SEEMS NOT TO WORK
if(strcmp((*(dynamicalData+j-1))->varName, buffer) == 0){
memset(buffer,'\0',10);
match = true; //match found
break;
}
else
match = false; //no match found
} //endForCycle
if(match == false){ //no match found
numOfVars++; //number of variables for allocation
tmpal = (varData*)realloc((*dynamicalData), numOfVars * sizeof(varData));
if(!tmpal) { //or equal to NULL
//printf("Could not resize/reallocate memory %i times \n", numOfVars);
}
else{
dynamicalData = tmpal;
strcpy((*(dynamicalData+numOfVars-1))->varName, buffer);
printf("%s \n", (*(dynamicalData+numOfVars-1))->varName);
}
}
}
varOrNum = 0; //if varOrNum is a number (1)
memset(buffer,'\0',10);
}
}
else{
buffer[i] = oneChar;
i++;
}
} //endWhileCycle (!feof(fSource))
fclose (fSource);
return numOfVars;
}
INSIDE INPUT FILE: u02v1_input_03.txt
0 -> c
va OR dq -> v
NOT cx -> dr
kk RSHIFT 3 -> km
NOT cx -> dq
3 AND v -> fx
lf RSHIFT 2 -> lg
Can anybody be so nice and help me with that? Thank you very much.
Try something like this:
if((varOrNum == 0) && (buffer[0] != '0')) {
int j;
for(j = 0; j<numOfVars; j++) {
if(strcmp(dynamicalData[j]->varName, buffer) == 0)
break;
}
if(j>=numOfVars) {
numOfVars++; //number of variables for allocation
tmpal = (varData*)realloc((*dynamicalData), numOfVars * sizeof(varData));
if(!tmpal) { //or equal to NULL
//printf("Could not resize/reallocate memory %i times \n", numOfVars);
}
else{
dynamicalData = tmpal;
strcpy(dynamicalData[numOfVars-1]->varName, buffer);
printf("%s \n", dynamicalData[numOfVars-1]->varName);
}
}
}
varOrNum = 0; //if varOrNum is a number (1)
memset(buffer,'\0',10);
In the 1st line you missed a &.
In the 1st loop (j==0) you do a strcmp dynamicalData+j-1 which means dynamicalData[-1]
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I am working on a school project which is basically creating a simple shell in UNIX.
But I'm stuck with history part of my project.The explanation which is about history part is explained below:
history – This command is for maintaining a history of commands previously issued.
o history - print up to the 10 most recently entered commands in your shell.
o ! number - A user should be able to repeat a previously issued command by
typing ! number, where number indicates which command to repeat.
Note that ! 1 is for repeating the command numbered 1 in the list of commands returned by
history, and ! -1 is for repeating the last command.
And my code till history part is here :
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <limits.h>
#include <malloc.h>
#include <string.h>
#include <termios.h>
#include <errno.h>
#define CREATE_FLAGS (O_WRONLY | O_CREAT | O_APPEND)
#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
#define CREATE_FLAG (O_WRONLY| O_CREAT| O_TRUNC)
#define MAXCHARNUM 128
#define MAXARGNUM 32
char *argsexec[MAXARGNUM];
char str[MAXCHARNUM];
char *path;
char *name;
struct Node
{
pid_t pid;
char *pname;
int index;
struct Node *nextPtr;
};
typedef struct Node Node;
typedef struct Node *NodePtr;
NodePtr list = NULL;
void addJob(NodePtr *currentPtr, pid_t pid, char *name, int indx)
{
NodePtr newPtr, prePtr, curPtr;
newPtr = malloc(sizeof(Node));
if (newPtr != NULL )
{
newPtr->pid = pid;
newPtr->pname = name;
newPtr->index = indx;
newPtr->nextPtr = NULL;
prePtr = NULL;
curPtr = *currentPtr;
while (curPtr != NULL )
{
prePtr = curPtr;
curPtr = curPtr->nextPtr;
}
if (prePtr == NULL )
{
newPtr->nextPtr = *currentPtr;
*currentPtr = newPtr;
}
else
{
prePtr->nextPtr = newPtr;
newPtr->nextPtr = curPtr;
}
}
}
void printJob(NodePtr curPtr)
{
if (curPtr == NULL )
{
printf("Running: List is empty.\n");
printf("Terminated: List is empty.\n");
}
else
{
printf("Running:\n");
while (curPtr != NULL )
{
printf("[%d] --> %s\n", curPtr->index, curPtr->pname);
curPtr = curPtr->nextPtr;
}
printf("Finished:\n");
while (curPtr != NULL )
{
printf("[%d] --> %s (pid = %d)\n", curPtr->index, curPtr->pname,
curPtr->pid);
curPtr = curPtr->nextPtr;
}
}
}
void ioredirection()
{
int input = -1, output = -1, append = -1;
int k, d, fdinput, fdoutput;
for (k = 0; argsexec[k] != NULL ; k++)
{
if (strcmp(argsexec[k], "<") == 0)
{
argsexec[k] = NULL;
input = k;
d = 1;
}
else if (strcmp(argsexec[k], ">") == 0)
{
argsexec[k] = NULL;
output = k;
d = 2;
}
else if (strcmp(argsexec[k], ">>") == 0)
{
argsexec[k] = NULL;
append = k;
d = 3;
}
if (d == 1)
{
fdinput = open(argsexec[input + 1], O_RDONLY, 0);
dup2(fdinput, STDIN_FILENO);
close(fdinput);
execvp(argsexec[0], argsexec);
}
if (d == 2)
{
int x, y;
char buffer[1024];
fdinput = open(argsexec[output - 1], O_RDONLY);
fdoutput = open(argsexec[output + 1], CREATE_FLAG, CREATE_MODE);
dup2(fdoutput, STDOUT_FILENO);
x = read(fdinput, buffer, 1024);
write(fdoutput, buffer, x);
close(fdinput);
close(fdoutput);
for (y = output; y < MAXARGNUM - 2; y++)
argsexec[y] = argsexec[y + 2];
argsexec[MAXARGNUM - 2] = NULL;
}
if (d == 3)
{
int x, y;
char buffer[1024];
fdinput = open(argsexec[output - 1], O_RDONLY);
fdoutput = open(argsexec[output + 1], CREATE_FLAGS, CREATE_MODE);
x = read(fdinput, buffer, 1024);
write(fdoutput, buffer, x);
close(fdinput);
close(fdoutput);
}
}
}
void add_path(char **dir, const char *begin, const char *end) //do the memory allocations, and add to the specified arrays.
{
if (end == begin)
{
begin = " ";
end = begin + 1;
}
size_t len = end - begin;
*dir = malloc(len + 1);
memmove(*dir, begin, len);
(*dir)[len] = '\0';
}
size_t tokenize(const char *path, char **dirs, size_t max_dirs, char delim) //tokenize the given input, with the given delimiter
{ //returns the size of the splitted parts of the string.
const char *begin = path;
const char *end;
size_t num_dirs = 0;
while (num_dirs < max_dirs && (end = strchr(begin, delim)) != 0)
{
add_path(&dirs[num_dirs++], begin, end);
begin = end + 1;
}
if (num_dirs < max_dirs && *begin != '\0')
add_path(&dirs[num_dirs++], begin, begin + strlen(begin));
return num_dirs;
}
void clearArgs()
{
int i;
for (i = 0; i < MAXARGNUM; ++i)
{
argsexec[i] = NULL;
}
}
int Ampersand()
{
int i;
for (i = 0; argsexec[i] != NULL ; i++)
{
if (strcmp(argsexec[i], "&") == 0)
{
return 1;
}
else
{
return 0;
}
}
}
void Setup()
{
while (1)
{
path = malloc((MAXCHARNUM + 1) * sizeof(char));
clearArgs();
fprintf(stderr, "333sh: ", NULL );
gets(str); //get the next commands
while (strlen(str) == 0)
{ //if the user enters empty string or space, ignore this input, read again.
fprintf(stderr, "333sh: ", NULL );
gets(str);
}
size_t commands = tokenize(str, argsexec, MAXARGNUM, ' ');
const char *path = getenv("PATH"); //get the system's path
ioredirection();
char * const arguments[] =
{ argsexec[0], argsexec[1], argsexec[2], argsexec[3], argsexec[4],
argsexec[5], argsexec[6], argsexec[7], (void*) NULL };
name = argsexec[0];
pid_t pid = fork();
wait(NULL );
if (Ampersand())
{
if (pid == 0)
{
int in = 1;
addJob(&list, pid, name, in);
}
}
if (pid == 0)
{
if (!Ampersand())
{
if (path == NULL )
{ //execl part
execl(path, argsexec[0], argsexec[1], argsexec[2], argsexec[3],
argsexec[4], argsexec[5], argsexec[6], argsexec[7], NULL );
}
else if (strcmp(argsexec[0], "dir") == 0 && argsexec[1] == NULL )
{
system("ls");
}
else if (strcmp(argsexec[0], "clr") == 0)
{
system("clear");
}
else if (strcmp(argsexec[0], "cd") == 0 && argsexec[1] == NULL )
{
system("pwd");
}
else if (strcmp(argsexec[0], "list_jobs") == 0 && argsexec[1] == NULL )
{
printJob(list);
}
else
{ //execvp part
execvp(argsexec[0], arguments);
}
}
}
}
}
int main(int argc, char const *argv[])
{
Setup();
return 0;
}
So how can i design a history part of this project ? Any idea would be appreciated.And sorry for asking that much long code.
Thanks
One way would be to create an array of 10 pointers to NULL initially. Add a routine update_history(<cmd issued>) or such that you call after every command you allow in your shell. It should:
(1) 1st call: malloc() space for the first command issued, and store the pointer to the
heap area in the array's first position
(2) Later calls: check the array for the first position with a NULL pointer, and store a pointer to the command there (using malloc() again). If you find no NULL pointer in the array (history is 10 commands long), go to (3)
(3) execute another new routine move_history(cmd issued). It moves the second array position (pointer) to the first, the 3rd to the 2nd, ..., the 10th to the 9th, and inserts a pointer to where <cmd_issued> is stored on the heap (using another malloc()) into the last array position. Don't forget to free() the heap memory that was allocated for the formerly first element that is no longer tracked.
You could then very easily print out the entire history (print through the array of pointers until you find a NULL pointer, but no more than 10 p/os; and print the command history numbers 1-10 (or 0-9) before the strings); and to print a particular command, you know in which array row the pointer to it is (if 1-based numbering, in row i-1). You can then read it and re-issue the command (don't forget to make that part of your history too).