Error ends_with(Stack* S, Stack* scope_arr) { require(2); V haystack = popS(); V needle = popS(); if (getType(needle) != T_STR || getType(haystack) != T_STR) { clear_ref(needle); clear_ref(haystack); return TypeError; } NewString *needle_s = toNewString(needle); NewString *haystack_s = toNewString(haystack); if (needle_s->size > haystack_s->size || memcmp(haystack_s->text + haystack_s->size - needle_s->size, needle_s->text, needle_s->size)) { pushS(add_ref(v_false)); } else { pushS(add_ref(v_true)); } clear_ref(needle); clear_ref(haystack); return Nothing; }
Error count(Stack* S, Stack* scope_arr) { require(2); V haystack = popS(); V needle = popS(); if (getType(haystack) != T_STR || getType(needle) != T_STR) { clear_ref(haystack); clear_ref(needle); return TypeError; } size_t haystack_len = toNewString(haystack)->size; size_t needle_len = toNewString(needle)->size; if (needle_len == 0) { pushS(int_to_value(string_length(toNewString(haystack)) + 1)); clear_ref(haystack); clear_ref(needle); return Nothing; } utf8 haystack_c = toNewString(haystack)->text; utf8 needle_c = toNewString(needle)->text; utf8index ix; int count = 0; for (ix = 0; ix < haystack_len - needle_len + 1; ) { if (!memcmp(haystack_c + ix, needle_c, needle_len)) { count++; ix += needle_len; } else { ix = nextchar(haystack_c, ix); } } pushS(int_to_value(count)); clear_ref(haystack); clear_ref(needle); return Nothing; }
Error chr(Stack* S, Stack* scope_arr) { require(1); V v = popS(); if (getType(v) != T_NUM) { clear_ref(v); return TypeError; } pushS(unichar_to_value(toNumber(v))); clear_ref(v); return Nothing; }
Error make_blob(Stack *S, Stack *scope_arr) { require(1); V v = popS(); if (getType(v) != T_NUM) { clear_ref(v); return TypeError; } pushS(new_blob(toNumber(v))); clear_ref(v); return Nothing; }
void popQ(Stack *s1, Stack *s2, char **c){ char *t; if(isEmptyS(s2)){ while(!(isEmptyS(s1))){ popS(s1, &t); pushS(s2, t); } } popS(s2, c); }
Error contains(Stack* S, Stack* scope_arr) { require(2); V haystack = popS(); V needle = popS(); if (getType(needle) != T_STR || getType(haystack) != T_STR) { clear_ref(needle); clear_ref(haystack); return TypeError; } NewString *needle_s = toNewString(needle); NewString *haystack_s = toNewString(haystack); if (string_length(needle_s) > string_length(haystack_s)) { pushS(add_ref(v_false)); } else { uint32_t i; utf8index index = 0; for (i = 0; i <= string_length(haystack_s) - string_length(needle_s); i++) { if (!memcmp(haystack_s->text + index, needle_s->text, needle_s->size)) { pushS(add_ref(v_true)); clear_ref(needle); clear_ref(haystack); return Nothing; } index = nextchar(haystack_s->text, index); } pushS(add_ref(v_false)); } clear_ref(needle); clear_ref(haystack); return Nothing; }
Error find(Stack* S, Stack* scope_arr) { require(2); V haystack = popS(); V needle = popS(); if (getType(needle) != T_STR || getType(haystack) != T_STR) { clear_ref(needle); clear_ref(haystack); return TypeError; } NewString *needle_s = toNewString(needle); NewString *haystack_s = toNewString(haystack); if (string_length(needle_s) <= string_length(haystack_s)) { size_t haystack_len = haystack_s->size; size_t needle_len = needle_s->size; utf8 haystack_c = haystack_s->text; utf8 needle_c = needle_s->text; utf8index ix; int i = 0; for (ix = 0; ix < haystack_len - needle_len + 1; ix = nextchar(haystack_c, ix)) { if (!memcmp(haystack_c + ix, needle_c, needle_len)) { pushS(int_to_value(i)); clear_ref(needle); clear_ref(haystack); return Nothing; } i++; } } pushS(int_to_value(-1)); clear_ref(needle); clear_ref(haystack); return Nothing; }
Error clone_blob_(Stack *S, Stack *scope_arr) { require(1); V blob = popS(); Error e = Nothing; if (getType(blob) != T_BLOB) { e = TypeError; goto cleanup; } pushS(clone_blob(blob)); cleanup: clear_ref(blob); return e; }
// Removes the string from the front of the queue and sets it to s void deQ(Queue *q, char **s) { if (isEmptyQ(q)) { DIE("Queue is empty"); } if (!isEmptyS(&(q->stack2))) { popS(&(q->stack2), s); } else { while (!isEmptyS(&(q->stack1))) { popS(&(q->stack1), s); pushS(&(q->stack2), *s); } popS(&(q->stack2), s); } }
Error ord(Stack* S, Stack* scope_arr) { require(1); V v = popS(); if (getType(v) != T_STR) { clear_ref(v); return TypeError; } NewString *s = toNewString(v); if (s->size == 0) { clear_ref(v); return ValueError; } utf8index n = 0; pushS(int_to_value(decode_codepoint(s->text, &n))); clear_ref(v); return Nothing; }
Error chars(Stack* S, Stack* scope_arr) { require(1); V source = popS(); if (getType(source) != T_STR) { clear_ref(source); return TypeError; } utf8 chrs = toNewString(source)->text; utf8index index = 0; V list = new_list(); Stack *st = toStack(list); size_t size = toNewString(source)->size; size_t i; for (i = 0; i < size; i++) { push(st, unichar_to_value(decode_codepoint(chrs, &index))); } pushS(list); return Nothing; }
Error getbyte_blob_(Stack *S, Stack *scope_arr) { require(2); V blob = popS(); V index = popS(); Error e = Nothing; if (getType(blob) != T_BLOB || getType(index) != T_NUM) { e = TypeError; goto cleanup; } int byte = getbyte_blob(blob, toNumber(index)); if (byte < 0) { set_error_msg("Index out of range"); e = ValueError; goto cleanup; } pushS(int_to_value(byte)); cleanup: clear_ref(blob); clear_ref(index); return e; }
/* Pops off string pointer in FIFO order by taking from Stack 2 if it has values and otherwise pouring all the values from Stack 1 into Stack 2 before popping off the top of Stack 2, which will be the first element pushed onto Stack 1. Returns TRUE if successful and puts popped value into *pos. */ bool dequeue (Stack *stk1, Stack *stk2, char **pos) { if (!isEmptyQ(stk1, stk2)) // The queue is NOT empty { if (!isEmptyS(stk2)) // stk2 has vals, pop off top one { popS(stk2, pos); return true; } else // No vals in stk2 { while (!isEmptyS(stk1)) // pour all of stk1 into stk2 { popS(stk1, pos); pushS(stk2, *pos); } popS(stk2, pos); // Now pop off top of stk2 return true; } } else return false; // Queue was empty }
/* Function: quicksort Arguments: A = the stack we want to be sorted B = the stack where we put the bigger values C = the stack where we put the smaller values flipped = for keeping the sort stable location = where the sorted stack is, from 1 to 3 counter = how many values have been pushed on this level pos = the value of POS len = the value of LEN Return Value: This function returns void Outside Effect: This function sorts the values in the A stack, which persists outside the function Description: This function performs quicksort using three stacks */ void quicksort(Stack *A, Stack *B, Stack *C, bool flipped, int location, int counter, int pos, int len) { // Base case if (counter == 0) { return; } char *splitter; // The splitter string // Pop off the splitter if (!isEmptyS(A)) { if (!popS(A, &splitter)) { DIE("Pop failed"); } counter--; } char *next = NULL; // The next string to be sorted int bigger = 0; // The number of pushes to B int smaller = 0; // The number of pushes to C // Split the stack into bigger and smaller while (counter > 0) { if (!popS(A, &next)) { DIE("Pop failed1"); } int comp; // The value of the comparsion comp = strcompare(splitter, next, pos, len); // Push the string to the bigger stack if (comp < 0) { if(!pushS(B, next)) { DIE("Push failed"); } bigger++; } // Push the string to the smaller stack else if (comp > 0) { if(!pushS(C, next)) { DIE("Push failed"); } smaller++; } // If strings are equal, perform stability check else { // If flipped, push the splitter if (flipped) { if(!pushS(B, splitter)) { DIE("Push failed"); } splitter = next; bigger++; } // Otherwise push the string else { if(!pushS(B, next)) { DIE("Push failed"); } bigger++; } } counter--; } // Swap the value of flipped each iteration flipped = !flipped; // Recursive step if (bigger == 0) { // Push to A, swap location 1 and 2, sort smallers if (location == 1) { if(!pushS(A, splitter)) { DIE("Push failed"); } if (smaller == 0) { return; } quicksort(C, A, B, flipped, 2, smaller, pos, len); } // Push to B, keep location the same, sort smallers else if (location == 2) { if(!pushS(B, splitter)) { DIE("Push failed"); } if (smaller == 0) { return; } quicksort(C, B, A, flipped, 2, smaller, pos, len); } } else { // Swap location 1 and 2, sort biggers, push to A, sort smallers if (location == 1) { quicksort(B, A, C, flipped, 2, bigger, pos, len); if(!pushS(A, splitter)) { DIE("Push failed"); } if (smaller == 0) { return; } quicksort(C, A, B, flipped, 2, smaller, pos, len); } // Keep location the same, sort biggers, push to B, sort smallers else if (location == 2) { quicksort(B, A, C, flipped, 1, bigger, pos, len); if(!pushS(B, splitter)) { DIE("Push failed"); } if (smaller == 0) { return; } quicksort(C, B, A, flipped, 2, smaller, pos, len); } } return; }
// Adds the string s to the queue void enQ(Queue *q, char *s) { pushS(&(q->stack1), s); }
int main(int argc, char * argv[]){ Stack stack1; Stack stack2; Stack stack3; createS(&stack1); createS(&stack2); createS(&stack3); int flipped = 1; //equals 1 if lines are in same relative order as in files, -1 if flipped int pos = 0; int len = INT_MAX; int filestart = 1; //variable is incremented if there is a len/pos key int nlines = 0; //Number of lines beeing sorted char * end; if( argc == 1 ){ exit(1); } if(argv[1][0] == '-'){ filestart +=1; pos = strtol(&argv[1][1],&end,10); if(end[0] != ',' && strlen(end) != 0){ DIE("Invalid input"); } else if (strlen(end) != 0 ){ len = strtol(&end[1],&end,10); printf("%d", len); } if (strlen(end) != 0){ DIE("Invalid input"); } } char * line; FILE * fp; for(int m=filestart; m < argc; m++) { if(argv[m][0] == '-'){ fp = stdin; } else if ((fp = fopen(argv[m],"r")) == NULL){ DIE("Cannot read file"); } while((line = getLine(fp)) != NULL){ remove_break(&line); if(!pushS(&stack1, line)){ DIE("pushS failed to execute"); } nlines += 1; } fclose(fp); } split(&stack2, &stack1, &stack3, nlines, pos, len, -1, flipped * -1); while(!isEmptyS(&stack2)){ popS(&stack2, &line); printf("%s", line); free(line); printf("\n"); } while(!isEmptyS(&stack1)){ popS(&stack1, &line); printf("%s", line); free(line); printf("\n"); } destroyS(&stack1); destroyS(&stack2); destroyS(&stack3); return 1; }
int main(int numargs, char *args[]){ //should have either 4, 5, 6, or 7 arguments //if 7, [1] must be -r, [2,3,4] must be ints, initial and goal are letters //if 6, must not include -r, include all else //if 5 must include -r and not height OR width //if 4, must have int for maxlength and letters for other, and nothing else //height and width are ints between 2 and 5 (Default is 3) //maxlength is non-negative int (can be 0) //INITIAL and GOAL have the necessary number of letters for the size of the tray //letters between only A and L (duplicates ok) int width = 3; //width of the tray, default is 3 int height = 3; //height of the tray, default is 3 int maxlength = -1; //maxlength of the pattern int tilelen; //number of tiles char *temp; bool flag; //true is -r is specified bool used; char *initial; //initial position char *goal; //goal position //if all the command-line args follow the rules for 4 args if((numargs == 4) && checkNum(args[1]) && checkTiles(args[2], args[3])){ maxlength = (int)strtol(args[1], &temp, 10); tilelen = strlen(args[2]); flag = false; //no flag present initial = args[2]; goal = args[3]; } //if all the command-line args follow the rules for 5 args else if((numargs == 5) && checkFlag(args[1]) && checkNum(args[2]) && checkTiles(args[3], args[4])){ maxlength = (int)strtol(args[2], &temp, 10); tilelen = strlen(args[3]); flag = true; //flag present initial = args[3]; goal = args[4]; } //if all the command-line args follow the rules for 6 args else if((numargs == 6) && checkNum(args[1]) && checkNum(args[2]) && checkNum(args[3]) && checkTiles(args[4], args[5])){ height = (int)strtol(args[1], &temp, 10); width = (int)strtol(args[2], &temp, 10); maxlength = (int)strtol(args[3], &temp, 10); tilelen = strlen(args[4]); flag = false; //no flag present initial = args[4]; goal = args[5]; } //if all the command-line args follow the rules for 7 args else if((numargs == 7) && checkFlag(args[1]) && checkNum(args[2]) && checkNum(args[3]) && checkNum(args[4]) && checkTiles(args[5], args[6])){ height = (int)strtol(args[2], &temp, 10); width = (int)strtol(args[3], &temp, 10); maxlength = (int)strtol(args[4], &temp, 10); tilelen = strlen(args[5]); flag = true; //flag present initial = args[5]; goal = args[6]; } else{//invalid command line args fprintf(stderr, "Invalid command line arguments\n"); exit(1); } if((height >= 2) && (height <= 5) && (width >= 2) && (width <= 5) && (tilelen == height*width)){} else{//if the height and width aren't right, then quit fprintf(stderr, "Invalid command line arguments\n"); exit(1); } Stack q1; //create the two stacks for the queue Stack q2; createS(&q1); createS(&q2); char *nextStr; //holds what is popped off queue 'P' int nextLen; //holds the length of P Trie root; //root of the trie dictionary root.len = -1; root.from = NULL; for(int k = 0; k < 12; k++) root.children[k] = NULL; insert(&root, goal, NULL, 0); //insert root in queue & dictionary pushS(&q1, goal); if(!(strcmp(goal, initial))){ //if goal is initial printf("%s\n", initial); destroyS(&q1); destroyS(&q2); return 0; } while(!(isEmptyS(&q1) && isEmptyS(&q2))){ //while queue not empty popQ(&q1, &q2, &nextStr); nextLen = lenInTrie(&root, nextStr); used = false; if(nextLen < maxlength){ //generate all the possible tiles for(int c = 0; c < width; c++){ //for all column shifts if(flag){//-r, then do it for all possible shifts for(int sh = 1; sh < width; sh++){ char *nextTiles = shiftC(nextStr, height, width, c, height - sh); //next tile pattern generated by a shift if(!strcmp(nextTiles, initial)){ insert(&root, nextTiles, nextStr, nextLen + 1); printSteps(root, nextTiles); destroyS(&q1); destroyS(&q2); return 0; } if(insert(&root, nextTiles, nextStr, nextLen + 1)){ pushS(&q1, nextTiles); //add it to the queue and dictionary used = true; } else free(nextTiles); } } else{//else do it for shift is one step only char *nextTiles = shiftC(nextStr, height, width, c, height - 1); //next tile pattern generated by a shift if(!strcmp(nextTiles, initial)){ insert(&root, nextTiles, nextStr, nextLen + 1); printSteps(root, nextTiles); destroyS(&q1); destroyS(&q2); return 0; } if(insert(&root, nextTiles, nextStr, nextLen + 1)){ pushS(&q1, nextTiles); //add it to the queue and dictionary used = true; } else free(nextTiles); } } for(int r = 0; r < height; r++){//for all possible row shifts if(flag){//-r, then do it for all possible shifts for(int sh = 1; sh < height; sh++){ char *nextTiles = shiftR(nextStr, height, width, r, width - sh); //next tile pattern generated by a shift if(!strcmp(nextTiles, initial)){ insert(&root, nextTiles, nextStr, nextLen + 1); printSteps(root, nextTiles); destroyS(&q1); destroyS(&q2); return 0; } if(insert(&root, nextTiles, nextStr, nextLen + 1)){ pushS(&q1, nextTiles); //add it to the queue and dictionary used = true; } else free(nextTiles); } } else{//else do it for shift is one step only char *nextTiles = shiftR(nextStr, height, width, r, width - 1); //next tile pattern generated by a shift if(!strcmp(nextTiles, initial)){ insert(&root, nextTiles, nextStr, nextLen + 1); printSteps(root, nextTiles); destroyS(&q1); destroyS(&q2); return 0; } if(insert(&root, nextTiles, nextStr, nextLen + 1)){ pushS(&q1, nextTiles); //add it to the queue and dictionary used = true; } else free(nextTiles); } } } if(!used) free(nextStr); }//end of while queue is not empty destroyS(&q1); destroyS(&q2); return 0; }
//The split function uses the first element of stack2 as a splitter //It puts all lines less than the splitter in stack 1 //All lines greater go in stack3 //the function sorts the number of lines equal to depth in stack2 //The stack1_pos variable keeps track of where the the solved stack is // if stack1_pos = 1 i push the splitters to stack 1 //if the stack1_pos = -1 i push the splitters to stack 2 Stack split(Stack * stack1,Stack * stack2,Stack * stack3, int depth,int pos,int len,int stack1_pos,int flipped){ char * splitter; char * line; int nless = 0; int ngreater = 0; int compare; if(depth == 0){ return NULL; } if(!popS(stack2, &splitter)){ DIE("PopS failed to execute"); } if(depth == 1){ if(stack1_pos == 1){ if(!pushS(stack1, splitter)){ DIE("pushS failed to execute"); } } else{ if(!pushS(stack2, splitter)){ DIE("pushS failed to execute"); } } return NULL; } for (int i = 1; i < depth; i++){ if(!popS(stack2, &line)){ DIE("popS failed to execute"); } //If the pos is greater than the length of both lines they are equal if (pos >= strlen(line) && pos >= strlen(splitter)){ compare = 0; } //If the pos is greater than only strlen(line) then the splitter is greater else if (pos >= strlen(line)){ compare = -1; } //If the pos is greater than only strlen(splitter) the line is greater else if (pos >= strlen(splitter)){ compare = 1; } else { compare = (strncmp(&line[pos],&splitter[pos], len)); } if (compare == 0){ printf("repeates\n\n\n\n\n\n\n\n"); if (flipped == -1){ ngreater += 1; if(!pushS(stack3,line)){ DIE("pushS failed to execute"); } } else{ nless += 1; if(!pushS(stack1,line)){ DIE("pushS failed to execue"); } } } else if (compare < 0){ ngreater += 1; pushS(stack3,line); } else{ pushS(stack1,line); nless += 1; } } split( stack2, stack1, stack3, nless, pos, len, stack1_pos * -1, flipped * -1); if(stack1_pos == 1){ pushS(stack1, splitter); } else{ pushS(stack2, splitter); } if (stack1_pos == 1){ split(stack1, stack3, stack2, ngreater, pos, len, stack1_pos, flipped * -1); } else { split(stack2, stack3, stack1, ngreater, pos, len, stack1_pos * -1, flipped * -1); } return NULL; }
int main(int argc, char *argv[]) { int pos = 0; // Value of POS, initialized at 0 int len = INT_MAX; // Value of LEN, initialized at INT_MAX // If there are no arguments, exit if (argc < 2) { exit(0); } int firstfile = 1; // The index of the first filename // Read in values of POS and LEN if they exist if (*argv[1] == '-') { // Fail if just a "-" with no numbers if (*(argv[1]+1) == '\0') { DIE("Invalid POS/LEN"); } char* next = NULL; // End pointer for strtol // Retrieve the POS value from argv pos = strtol(argv[1]+1, &next, 10); if (*next == ',') { if (*(next+1) != '\0') { char* check = NULL; // Second end pointer for strtol // Retrieve the LEN value from the first end pointer len = strtol(next+1, &check, 10); // Fail if there are characters after "-POS,LEN" if (*check != '\0') { DIE("Invalid POS/LEN"); } } // Fail if just "-POS," else { DIE("Invalid POS/LEN"); } } // Fail if there is a non-comma value after POS else if (*next != '\0') { DIE("Invalid POS/LEN"); } firstfile++; } Stack A, B, C; // The three stack pointers // Create the stacks if (!createS(&A) || !createS(&B) || !createS(&C)) { DIE("Create stack failed"); } int numLines = 0; // The number of lines read FILE* file = NULL; // The current file pointer // File reading loop for (int i = firstfile; i < argc; i++) { file = fopen(argv[i], "r"); if (file == NULL) { DIE("Unreadable File"); } char* line; // The current line pointer // Line reading loop while ((line = getLine(file)) != NULL) { char* newline = strchr(line, '\n'); // Pointer to check for newlines // Remove trailing newlines if (newline != NULL) { *newline = '\0'; } // Push the lines into stack A if (!pushS(&A, line)) { DIE("Push failed"); } numLines++; } fclose(file); } quicksort(&A, &B, &C, true, 1, numLines, pos, len); // Line printing loop for (int i = 0; i < numLines; i++) { char *line; // The current line to print // Pop off a line to be printed if (!popS(&A, &line)) { DIE("Pop failed"); } fprintf(stdout, "%s\n", line); free(line); } // Destroy the stacks if (!destroyS(&A) || !destroyS(&B) || !destroyS(&C)) { DIE("Destroy stack failed"); } }
/* Adds string pointer to the top of Stack 1. Per the spec, we can assume this operation will not fail. Returns TRUE. */ bool enqueue (Stack *stk1, Stack *stk2, char *pos) { pushS(stk1, pos); return true; }