#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#define boolean int
#define false 0
#define true 1
#ifdef linux
#define clear() printf("\x1B[2J\x1B[H")
#else
#define clear() system("cls")
#endif
//Utilitary
boolean isDigit(char c);
short int charToDigit(char c);
int length(char* str);
boolean contains(char c, char* array);
void checkMemoryFault(void* ptr);
boolean isLargerThan(char* word1, char* word2);
char toLowercase(char c);
//Input functions
char* gets();
int getUnsIntOrDefault();
//pGUI
int dmenu(int n, char* entries[n]);
int startMenu();
int workMenu();
int inputMenu();
//UX
void printErrorAndExit(char* message);
void clearToHeader();
void askEnter();
void printText(char** text, int length);
//Common outputs
void printHeader();
void printTask();
void wrongInputMessage(char* addInfo);
void sayGoodbye();
//Real logic
boolean workLoop();
void inputData(char** sepStorage, char*** textStorage, int* textLengthStorage);
void formNewText(char* separators, char** inText, int inTextLength, char*** newTextStorage, int* newTextLengthStorage);
//Some work with text
void splitString(char* str, char* separators, char*** wordsStorage, char*** sepseqStorage, int* wordsCount);
void sortWords(char** words, int wordsCount);
char* assemble(char** words, char** sepseqs, int wordsCount);
boolean trimShortestOrSignal(char** words, int wordsCount);
int main(){
boolean exitRequested = false;
int answer;
while(!exitRequested){
clearToHeader();
answer = startMenu();
switch(answer){
case -1:
wrongInputMessage("");
break;
case 0:
printTask();
askEnter();
break;
case 1:
exitRequested = workLoop();
break;
case 2:
exitRequested = true;
break;
}
}
sayGoodbye();
return 0;
}
//----
//Logic
//----
boolean workLoop(){
boolean isGlobalExitRequested = false;
char* separators = NULL;
char** inText = NULL;
int inTextLength;
char** newText = NULL;
int newTextLength;
boolean isFormed = false;
inputData(&separators, &inText, &inTextLength);
checkMemoryFault((void*) separators);
checkMemoryFault((void*) inText);
boolean exitRequested = false;
int answer;
while(!exitRequested){
clearToHeader();
answer = workMenu();
switch(answer){
case -1:
wrongInputMessage("");
break;
case 0:
printTask();
askEnter();
break;
case 1:
printText(inText, inTextLength);
askEnter();
break;
case 2:
if(!isFormed){
formNewText(separators, inText, inTextLength, &newText, &newTextLength);
checkMemoryFault(newText);
isFormed = true;
}
printText(newText, newTextLength);
askEnter();
break;
case 3:
printf("\nИсходный текст:\n");
printText(inText, inTextLength);
if(!isFormed){
formNewText(separators, inText, inTextLength, &newText, &newTextLength);
checkMemoryFault(newText);
isFormed = true;
}
printf("Cформированный текст:\n");
printText(newText, newTextLength);
askEnter();
break;
case 4:
printf("Символы-разделители: %s\n", separators);
askEnter();
break;
case 5:
exitRequested = true;
break;
case 6:
isGlobalExitRequested = true;
exitRequested = true;
break;
}
}
free(separators);
int i;
for(i=0; i<inTextLength; i++){
free(inText[i]);
}
free(inText);
if(isFormed){
for(i=0; i<newTextLength; i++){
free(newText[i]);
}
free(newText);
}
return isGlobalExitRequested;
}
void inputData(char** sepStorage, char*** textStorage, int* textLengthStorage){
checkMemoryFault(sepStorage);
(*sepStorage) = NULL;
checkMemoryFault(textStorage);
(*textStorage) = NULL;
checkMemoryFault(textLengthStorage);
boolean exitRequested = false;
int answer;
while(!exitRequested){
clearToHeader();
printf("Введите символы-разделители: ");
(*sepStorage) = gets();
checkMemoryFault(*sepStorage);
if((*sepStorage)[0]=='\0'){
wrongInputMessage("Разделителей должно быть ненулевое количество.\n");
}else{//continue
printf("\n");
printf("Введите количество строк в тексте: ");
(*textLengthStorage) = getUnsIntOrDefault(-1);
if((*textLengthStorage)<=0){
wrongInputMessage("Ожидалось, что вы введёте число (большее нуля).\n");
}else{//continue
printf("\n");
(*textStorage) = (char**) malloc( (*textLengthStorage) * sizeof(char*) );
checkMemoryFault(*textStorage);
int i;
for(i=0; i<(*textLengthStorage); i++){
printf("Введите строку №%d: ", (i+1));
(*textStorage)[i] = gets();
checkMemoryFault((*textStorage)[i]);
}
printf("\n");
answer = inputMenu();
switch(answer){
case -1:
wrongInputMessage("Введённые даные будут сохранены.\n");
exitRequested = true;
break;
case 0:
exitRequested = true;
break;
case 1:
//do nothing
break;
}
}}
}
}
void formNewText(char* separators, char** inText, int inTextLength, char*** newTextStorage, int* newTextLengthStorage){
checkMemoryFault((void*) separators);
checkMemoryFault((void*) inText);
if(inTextLength<=0){
printErrorAndExit("Произошла внутренняя ошибка.\n");
}
int i;
for(i=0; i<inTextLength; i++){
checkMemoryFault((void*) inText[i]);
}
checkMemoryFault((void*) newTextStorage);
(*newTextStorage) = NULL;
checkMemoryFault((void*) newTextLengthStorage);
char** words;
char** sepseqs;
int wordsCount;
int j; boolean haveToDelete;
(*newTextLengthStorage)=0;
for(i=0; i<inTextLength; i++){
splitString(inText[i], separators, &words, &sepseqs, &wordsCount);
if(wordsCount!=0) checkMemoryFault(words);
checkMemoryFault(sepseqs);
for(j=0; j<wordsCount+1; j++){
if(j!=wordsCount) checkMemoryFault(words[j]);
checkMemoryFault(sepseqs[j]);
}
haveToDelete = (wordsCount==0)
?false
:trimShortestOrSignal(words, wordsCount);
if(!haveToDelete){
if(wordsCount>1) sortWords(words, wordsCount);
(*newTextStorage) = (char**) realloc((*newTextStorage), ((*newTextLengthStorage)+1)*sizeof(char*));
(*newTextStorage)[(*newTextLengthStorage)] = assemble(words, sepseqs, wordsCount);
(*newTextLengthStorage)++;
}
}
}
void splitString(char* str, char* separators, char*** wordsStorage, char*** sepseqStorage, int* wordsCount){
checkMemoryFault((void*) str);
checkMemoryFault((void*) separators);
checkMemoryFault((void*) wordsStorage);
checkMemoryFault((void*) sepseqStorage);
checkMemoryFault((void*) wordsCount);
*wordsStorage = NULL;
*sepseqStorage = (char**) malloc(sizeof(char*));
checkMemoryFault((void*) *sepseqStorage);
(*wordsCount) = 0;
boolean isReadingWord = false;
boolean isEndOfSeq=false;
char* curSeq = (char*) malloc(sizeof(char));
checkMemoryFault((void*) curSeq);
int curSeqSize = 0;
int i=-1; //it will be immediately increased to 0
do{
i++;
if(isReadingWord){
if(contains(str[i], separators) || str[i]=='\0'){
isReadingWord = false; //Word is readen now
curSeq[curSeqSize]='\0';
(*wordsStorage)[*wordsCount] = curSeq;
(*wordsCount)++ ;
//String anyway ends with sep.seq., not word -- so THERE IS sep.seq. after ANY word
*sepseqStorage = (char**) realloc(*sepseqStorage, (*wordsCount+1)*sizeof(char*));
checkMemoryFault((void*) *sepseqStorage);
if(str[i]!='\0'){
//get ready to new input
isEndOfSeq = true; //Flag to flush curSeq
}
}else{
isEndOfSeq = false;
}
}else{
if(!contains(str[i], separators)){
isReadingWord = true; //Separators sequence is readen now
curSeq[curSeqSize]='\0';
(*sepseqStorage)[*wordsCount] = curSeq;
if(str[i]!='\0'){
//get ready to new input
*wordsStorage = (char**) realloc(*wordsStorage, (*wordsCount+1)*sizeof(char*));
checkMemoryFault((void*) *wordsStorage);
isEndOfSeq = true; //Flag to flush curSeq
}
}else{
isEndOfSeq = false;
}
}
if(isEndOfSeq){
curSeq = (char*) malloc(sizeof(char));
checkMemoryFault((void*) curSeq);
curSeqSize=0;
}
//Regular actions -- just remember our char
if(str[i]!='\0'){ //No need to remember that \0 ;)
curSeq[curSeqSize] = str[i];
curSeq = (char*) realloc(curSeq, sizeof(char)*(++curSeqSize+1));
checkMemoryFault((void*) curSeq);
}
}while(str[i]!='\0');
if(!isReadingWord){
//So, we have an empty last separators sequence
(*sepseqStorage)[*wordsCount] = (char*) malloc(sizeof(char));
checkMemoryFault((void*) (*sepseqStorage)[*wordsCount]);
(*sepseqStorage)[*wordsCount][0] = '\0';
}
}
boolean trimShortestOrSignal(char** words, int countWords){
checkMemoryFault(words);
int i;
for(i=0; i<countWords; i++){
checkMemoryFault(words[i]);
}
if(countWords<=0){
printErrorAndExit("Произошла внутренняя ошибка.\n");
}
int ind1;
if(countWords == 1){
int min=INT_MAX;
int count = 0;
ind1 = -1;
int len;
for(i=0; i<countWords; i++){
len = length(words[i]);
if(len<min){
min = len;
count = 1;
ind1 = i;
}else if(len == min){
count++;
}
}
if(count>1) return true;
}else{
ind1 = 0;
}
free(words[ind1]);
words[ind1] = (char*) malloc(sizeof(char));
checkMemoryFault(words[0]);
words[ind1][0]='\0';
return false;
}
void sortWords(char** words, int wordsCount){
if(wordsCount<2) return;
checkMemoryFault(words);
int i;
for(i=0; i<wordsCount; i++){
checkMemoryFault(words[i]);
}
i=0;
char* swap;
while(i+1<wordsCount){
if(isLargerThan(words[i+1], words[i])){
swap = words[i+1];
words[i+1] = words[i];
words[i] = swap;
if(i>0){
i--;
}else{
i++;
}
}else{
i++;
}
}
}
char* assemble(char** words, char** separators, int wordsCount){
if(wordsCount!=0) checkMemoryFault(words);
checkMemoryFault(separators);
char* str = (char*) malloc(sizeof(char));
checkMemoryFault(str);
int size=0;
int i,j;
for(i=0; i<wordsCount+1; i++){
j=0;
checkMemoryFault(separators[i]);
while(separators[i][j]!='\0'){
str[size] = separators[i][j];
str = (char*) realloc(str, sizeof(char)*(++size+1));
checkMemoryFault(str);
j++;
}
if(i!=wordsCount){
j=0;
checkMemoryFault(words[i]);
while(words[i][j]!='\0'){
str[size] = words[i][j];
str = (char*) realloc(str, sizeof(char)*(++size+1));
checkMemoryFault(str);
j++;
}
}
}
str[size]='\0';
return str;
}
//----
//Helpful littlies
//----
void checkMemoryFault(void* ptr){
if(ptr == NULL){
printErrorAndExit("Ошибка при работе с памятью. ");
}
}
void printErrorAndExit(char* message){
printf("%sПосле нажатия Enter программа завершит своё выполнение.\n", message);
askEnter();
exit(-1);
}
void clearToHeader(){
clear();
printHeader();
}
void askEnter(){
printf("Нажмите Enter для продолжения...");
getchar();
}
int length(char* str){
checkMemoryFault((void*)str);
int i=0;
while(str[i]!='\0'){
i++;
}
return i;
}
boolean isDigit(char c){
if(c<48 || c>57) return false;
return true;
}
short int charToDigit(char c){
return ((short int)c)-48;
}
boolean contains(char c, char* array){
checkMemoryFault(array);
int i=0;
while(array[i]!='\0'){
if(c == array[i]) return true;
i++;
}
return false;
}
void printText(char** text, int length){
checkMemoryFault((void*) text);
printf("\n");
int i;
for(i=0; i<length; i++){
checkMemoryFault((void*) text[i]);
printf("%s\n", text[i]);
}
printf("\n");
}
boolean isLargerThan(char* word1, char* word2){
checkMemoryFault(word1);
checkMemoryFault(word2);
if(word1[0]=='\0') return false;
if(word2[0]=='\0') return true;
int i = 0;
while(word1[i]!='\0' && word2[i]!='\0'){
if((int) toLowercase(word1[i]) != (int) toLowercase(word2[i])){
return ((int) toLowercase(word1[i]) < (int) toLowercase(word2[i]));
}
i++;
}
if(word1[i]=='\0'){
return true;
}
return false;
}
char toLowercase(char c){
//assert letters are given
if(((int)c)<97) return (char)((int)c + 32);
return c;
}
//----
//Input functions
//----
char* gets(){
char* str = (char*) malloc(sizeof(char));
checkMemoryFault(str);
int i = 0;
while( (str[i] = getchar()) != '\n' ){
str = (char*) realloc(str, sizeof(char)*(++i+1));
checkMemoryFault(str);
}
str[i]='\0';
return str;
}
int getUnsIntOrDefault(int defaultValue){
int ret = 0;
char c;
boolean isDefault = false;
while( (c = getchar()) != '\n' ){
if(!isDigit(c)){
isDefault = true;
}
if(!isDefault){
ret *= 10;
ret += charToDigit(c);
}
}
if(isDefault){
return defaultValue;
}
return ret;
}
void wrongInputMessage(char* addInfo){
printf("Не удалось распознать ввод. %s", addInfo);
askEnter();
}
//----
//pGUI
//----
int startMenu(){
char* entries[3]={"Вывести текст задания", "Ввести данные и начать работу с ними", "Завершить работу"};
return dmenu(3, entries);
}
int workMenu(){
char* entries[7]={"Вывести текст задания", "Вывести исходный текст", "Вывести сформированный текст", "Вывести оба (исходный и сформированный) текста", "Вывести символы-разделители", "Завершить работу с введёнными данными", "Завершить работу программы"};
return dmenu(7, entries);
}
int inputMenu(){
char* entries[2]={"Продолжить работу", "Ввести данные заново"};
return dmenu(2, entries);
}
int dmenu(int n, char* entries[n]){
printf("Выберите действие из меню, путём ввода его номера.\n");
int i;
for(i=0; i<n; i++){
printf("%d. %s\n", i+1, entries[i]);
}
printf("Ваш выбор: ");
int result = getUnsIntOrDefault(-1);
//Checking correctness
if(result<=0 || result>n) return -1;
return result-1;
}
//----
//Common outputs
//----
void printHeader(){
printf("----------------------------------------------------\n");
printf("Курсовая работа за первый семестр \t /\\_/\\\n");
printf("Вариант №18 \t=( °w° )=\n");
printf("Выполнил Соковых Пётр \t ) ( //\n");
printf("Факультет КТИ, группа 6305 \t (__ __)//\n");
printf("----------------------------------------------------\n");
}
void printTask(){
printf("\nЗадание:\n\n");
printf("Ввести строку символов разделителей и массив строк текста с заданным количесвтом строк. ");
printf("Из строк введённого текста сформировать другой текст, в котором слова будут распологаться ");
printf("в алфавитном порядке с сохранением очередности расположения символов разделителей в исходных строках. ");
printf("Одновременно из строк удалить слова с минимальным в этой строке количеством символов и всю строку, ");
printf("если таких слов в строке более одного.");
printf("Вывести исходный и сформированный текст.\n\n");
}
void sayGoodbye(){
printf("\nРабота завершена.\n");
}