How to implement `.nf` formatting feature - c

I have written a program that reads a text file inputted by the user, and inside the file contains formatting features such as .br , .sp and .nf.
.nf symbolises no fill, also meaning that when you see any formatting feature after .nf they should all be ignored and it should just output the text in the format it originally appears in the text file.
For example:
.nf Hello my name is .br Jay.
Output:
Hello my name is Jay
If .nf was not there the output would be:
Hello my name is
Jay.
Here's my code:
int main(void) {
FILE *fp = NULL;
char file_name[257] = {'\0'};
char line[61] = {'\0'};
char word[61] = {'\0'};
int out = 0;
int blanks;
int space;
int useFormats = 1;
printf ( "Enter file name:\n");
scanf ( " %256[^\n]", file_name);
if ( ( fp = fopen ( file_name, "r")) == NULL) {
printf ( "could not open file\n");
return 1;
}
while (useFormats == 1){
while ( ( fscanf ( fp, "%60s", word)) == 1) { //breaks the sentence after .br
if ( strcmp ( word, ".br") == 0) {
printf ( "%s\n", line);
line[0] = '\0';
out = 1;
}
if ( strcmp ( word, ".nf") == 0) {// stop filling lines (no fill)
useFormats == 0;
line[0] = '\0';
out = 1;
}
if ( strncmp ( word, ".sp", 3) == 0) { // creates n amount of spaces after .sp
if ( ( sscanf ( &word[3], "%d", &blanks)) == 1) {
printf ( "%s\n", line);
while ( blanks) {
blanks--;
printf ( "\n");
}
line[0] = '\0';
out = 1;
}
else {
printf ( "%s\n", line);
line[0] = '\0';
out = 1;
}
}
else if ( strlen ( line) + strlen ( word) + 1 < 60) {
strcat ( line, " ");
strcat ( line, word);
out = 0;
}
else {
printf ( "%s\n", line);
strcpy ( line, word);
out = 1;
}
}
if ( !out) {
printf ( "%s\n", line);
}
fclose ( fp);
return 0;
}
}
I tried creating a variable called useFormats which is true whilst running and I make it false when it reaches to the .nf feature but nothing happens. I'm not sure if I should remove the if statement and create another while loop to say while (useFormats == 0) to implement the .nf feature.

This should capture the ".nf" token and set useFormats to zero. Adding if ( useFormats == 1) { to the other format conditions should disable them.
#include <stdio.h>
#include <string.h>
#define WIDTH 80
int main(void) {
FILE *fp = NULL;
char file_name[257] = {'\0'};
char line[61] = {'\0'};
char word[61] = {'\0'};
int out = 0;
int blanks = 0;
int center = 0;
int useFormats = 1;
int margin = 0;
printf ( "Enter file name:\n");
scanf ( " %256[^\n]", file_name);
if ( ( fp = fopen ( file_name, "r")) == NULL) {
printf ( "could not open file\n");
return 1;
}
while ( ( fscanf ( fp, "%60s", word)) == 1) {// read file to end one word at a time
if ( strcmp ( word, ".nf") == 0) {// no formatting)
useFormats = 0;
center = 0;
continue;
}
if ( strncmp ( word, ".ce", 3) == 0) {
if ( useFormats == 1) {
if ( ( sscanf ( &word[3], "%d", &center)) != 1) {
center = 0;
}
}
continue;
}
if ( strncmp ( word, ".sp", 3) == 0) {
if ( useFormats == 1) {
if ( ( sscanf ( &word[3], "%d", &blanks)) == 1) {
margin = 0;
if ( center) {
margin = WIDTH - ( ( WIDTH - strlen ( line)) / 2);
center--;
}
printf ( "%*s\n", margin, line);
while ( blanks) {
blanks--;
printf ( "\n");
}
line[0] = '\0';
out = 1;
}
else {
margin = 0;
if ( center) {
margin = WIDTH - ( ( WIDTH - strlen ( line)) / 2);
center--;
}
printf ( "%*s\n", margin, line);
line[0] = '\0';
out = 1;
}
}
continue;
}
if ( strcmp ( word, ".br") == 0) {
if ( useFormats == 1) {
margin = 0;
if ( center) {
margin = WIDTH - ( ( WIDTH - strlen ( line)) / 2);
center--;
}
printf ( "%*s\n", margin, line);
line[0] = '\0';
out = 1;
}
continue;
}
if ( strlen ( line) + strlen ( word) + 1 <= 60) {
strcat ( line, " ");
strcat ( line, word);
out = 0;
}
else {
margin = 0;
if ( center) {
margin = WIDTH - ( ( WIDTH - strlen ( line)) / 2);
center--;
}
printf ( "%*s\n", margin, line);
strcpy ( line, word);
out = 1;
}
}
if ( !out) {
margin = 0;
if ( center) {
margin = ( WIDTH - strlen ( line)) / 2;
center--;
}
printf ( "%*s\n", margin, line);
}
fclose ( fp);
return 0;
}

As long as this: while ( ( fscanf ( fp, "%60s", word)) == 1) evaluates as true it will never break from the while current inner while loop. You can break out of the inner while loop with break; after your condition is met. It will then check the condition and break out of the main while loop. You also don't assign a value with ==. That operand is for evaluation.
if ( strcmp ( word, ".nf") == 0) {// stop filling lines (no fill)
useFormats = 0;
line[0] = '\0';
out = 1;
break;
}

Related

C program to find the duplicate values from an m×n matrix using malloc() and free()

SO i was solving this problem and i get this output
**But i am expecting output like this **
what is my mistake here?
I know i don't code efficiently and i want to know how can i make this code more compact any suggestions will be helpful as i am still learning these things.
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
int main()
{
int i,j,k,l,f=0,x=0,q=0,row,column,size;
int res[100];
printf("Enter the row: ");
scanf("%d",&row);
printf("Enter the column: ");
scanf("%d",&column);
size= row*column;
int **arr;
arr=(int**)malloc(row * sizeof(int));
for(i=0;i<row;i++)
{
arr[i] = (int*)malloc(column*sizeof(int));
}
for(i=0;i<row;i++)
{
for (j=0;j<column;j++)
{
printf("Enter the value at row %d and column %d : ",i,j);
scanf("%d",(*(arr+i)+j));
}
}
for(i=0;i<row;i++)
{
for (j=0;j<column;j++)
{
printf("\nThe value at row %d and column %d : %d",i,j,*(*(arr+i)+j));
}
}
printf("\nThe duplicate value(s) are:\n");
for(i=0; i<row; i++)
{
for(j=0; j<column; j++)
{
for(k=0; k<row; k++)
{
for(l=0; l<column; l++)
{
if(*(*(arr+i)+j)== *(*(arr+k)+l))
{
f=f+1;
}
if(f>1)
{
printf("%d in positions (%d,%d)",*(*(arr+i)+j),k,l);
}
}
}f=0;
}
}
free(arr);
}
This is closer to the original code.
skip duplicates that are found closer to the beginning of arr so those are only printed once.
Use a first flag to print the first indices of the first pair of matching values.
pending stores a set of indices to defer printing. This allows printing the last set of indices with a leading and while printing any other indices with a leanding comma.
#include<stdio.h>
#include<stdlib.h>
int scanint ( int *value) {
int result = 0;
result = scanf ( "%d", value);//ampersand not needed. value is int *
if ( 0 == result) {//could not parse an int from input
while ( '\n' != ( result = getchar ( ))) {//read until newline
if ( EOF == result) {
fprintf ( stderr, "EOF\n");
exit ( EXIT_FAILURE);
}
}
return 0;
}
return 1;
}
int main()
{
int eachrow = 0;
int eachcol = 0;
int row = 0;
int column = 0;
int result = 0;
do {
printf ( "Enter the row: ");
fflush ( stdout);
result = scanint ( &row);
} while ( 0 == result);
do {
printf ( "Enter the column: ");
fflush ( stdout);
result = scanint ( &column);
} while ( 0 == result);
int **arr = NULL;
if ( NULL == ( arr = malloc ( sizeof *arr * row))) {
fprintf ( stderr, "malloc arr problem\n");
exit ( EXIT_FAILURE);
}
for ( eachrow = 0; eachrow < row; ++eachrow) {
if ( NULL == ( arr[eachrow] = malloc ( sizeof **arr * column))) {
fprintf ( stderr, "malloc arr[] problem\n");
while ( eachrow) {
eachrow--;
free ( arr[eachrow]);
}
free ( arr);
exit ( EXIT_FAILURE);
}
}
for ( eachrow = 0; eachrow < row; ++eachrow) {
for ( eachcol = 0; eachcol < column; ++eachcol) {
do {
printf ( "Enter the value for (%d %d) : ", eachrow, eachcol);
fflush ( stdout);
result = scanint ( &arr[eachrow][eachcol]);
} while ( 0 == result);
}
}
for ( eachrow = 0; eachrow < row; ++eachrow) {
for ( eachcol = 0; eachcol < column; ++eachcol) {
printf ( "The value at (%d %d) : %d\n", eachrow, eachcol, arr[eachrow][eachcol]);
}
}
char pending[30] = "";
int checkrow = 0;
int checkcol = 0;
int skip = 0;
int first = 0;
int title = 0;
int line = 1;
for ( eachrow = 0; eachrow < row; ++eachrow) {
for ( eachcol = 0; eachcol < column; ++eachcol) {
first = 0;//will need to print the first part of line
pending[0] = 0;//nothing pending
for ( checkrow = 0; checkrow < row; ++checkrow) {
skip = 0;//do not skip
for ( checkcol = 0; checkcol < column; ++checkcol) {
if ( arr[eachrow][eachcol] == arr[checkrow][checkcol]) {//match
if ( checkrow * column + checkcol > eachrow * column + eachcol) {//subsequent match
if ( ! title) {
title = 1;
printf ( "\nThe duplicate value(s) are:\n");
}
if ( ! first) {//need to print first part of line
first = 1;//printed
printf ( "%d. %d in positions (%d,%d)"
, line, arr[eachrow][eachcol], eachrow, eachcol);
}
if ( pending[0]) {//print pending indices
printf ( ", %s", pending);
}
sprintf ( pending, "(%d,%d)", checkrow, checkcol);//copy indices to pending
}
else {//current or previous match
//ignore current match ( checkrow * column + checkcol == eachrow * column + eachcol)
if ( checkrow * column + checkcol < eachrow * column + eachcol) {//previous match
skip = 1;//need to skip checkcol and checkrow
break;//out of for checkcol loop
}
}
}
}
if ( skip) {
break;//out of checkrow loop
}
}
if ( first) {//there were matches
printf ( " and %s\n", pending);//print and with pending indices
}
}
}
if ( ! title) {
printf ( "\nNo duplicates\n");
}
for ( eachrow = 0; eachrow < row; ++eachrow) {
free ( arr[eachrow]);
}
free(arr);
}

output is different when I use default value vs user input

I am doing some pattern searching in a string for my homework. When I was testing the code, I declared a default value for easy testing. When I am done with the testing and tried to run the code using user input, the output is different.
The output (when used default value) "Match at position 4." but when use user input, it says "no match".
This is my code:
int main() {
char text[255], pattern[255];
char sensitive = 'N';
int n, a[255], i, j, k = 0, l, found = 0, t = 0, temp=0;
printf("Enter a sentence , up to 255 characters:");
fgets(text, 255, stdin);
text[strcspn(text, "\n")] = 0;
printf("Enter a pattern , up to 255 characters:");
fgets(pattern, 255, stdin);
pattern[strcspn(pattern, "\n")] = 0;
printf("Should the match be case-sensitive, Y or N?");
scanf("%c", &sensitive);
if (sensitive == 'N' || sensitive == 'n') {
for (i = 0; i < strlen(text); i++) {
text[i] = tolower(text[i]);
//printf("%c", text[i]);
}
for (i = 0; i < strlen(pattern); i++) {
pattern[i] = tolower(pattern[i]);
//printf("%c", pattern[i]);
}
}
for (i = 0;text[i] != '\0';i++)
{
j = 0;
if (text[i] == pattern[j] || pattern[j] == '.')
{
temp = i + 1;
while (text[i] == pattern[j] || pattern[j] == '.')
{
i++;
j++;
}
if (pattern[j] == '\0')
{
temp -= 1;
printf("Matches at position %d\n", temp);
exit(0);
}
else
{
i = temp;
temp = 0;
}
}
}
if (temp == 0)
printf("No match.\n");
return 0;
}
This tests if text or pattern are at the terminating zero so the index does not go beyond the array boundary.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main ( void) {
char text[255], pattern[255];
char sensitive[3] = "N";
int i, j, temp=0;
printf ( "Enter a sentence , up to 255 characters:");
if ( ! fgets(text, 255, stdin)) {
fprintf ( stderr, "fgets problem [text]\n");
return 0;
}
text[strcspn(text, "\n")] = 0;
printf ( "Enter a pattern , up to 255 characters:");
if ( ! fgets(pattern, 255, stdin)) {
fprintf ( stderr, "fgets problem [pattern]\n");
return 0;
}
pattern[strcspn(pattern, "\n")] = 0;//remove newline
printf ( "Should the match be case-sensitive, Y or N?");
if ( ! fgets( sensitive, sizeof sensitive, stdin)) {
fprintf ( stderr, "fgets problem [sensitive]\n");
return 0;
}
if ( sensitive[0] == 'N' || sensitive[0] == 'n') {
for ( i = 0; text[i]; i++) {
text[i] = tolower(text[i]);
}
for (i = 0; pattern[i]; i++) {
pattern[i] = tolower(pattern[i]);
}
}
for ( i = 0; text[i] != '\0';i++) {
j = 0;
temp = i + 1;
while ( pattern[j] && text[i + j]
&& ( text[i + j] == pattern[j] || pattern[j] == '.')) {
j++;
}
if (pattern[j] == '\0') {
temp -= 1;
printf("Matches at position %d\n", temp);
exit(0);
}
else {
temp = 0;
}
}
if (temp == 0) {
printf("No match.\n");
}
return 0;
}

Insert an element in a specified position in a given array

How can I insert a value in specific position in C?
For example:
const char filenameC[] ="AndModel.c";
FILE * fileC=fopen(filenameC,"r");
int LineNumber=1;
char line[200],search_string[]="similar";
if( fileC)
{
while ( fgets ( line, 200, fileC ) != NULL )
{
if(strstr(line,search_string))
{
fputs ( line, stdout );
printf("%d", LineNumber);
}
LineNumber++;
}
}
FILE * fileW=fopen(filenameC,"w");
fseek(fileW, LineNumber,SEEK_SET);
fputs("hello",fileW);
printf("\n");
return 0;
Alright here's your solution:
for (int i = number_of_elements -1; i >= desired_position; i--)
{
line[i + 1] = line[i];
}
line[desired_position] = value;
So in the case of your code, if I wanted to insert an element of the array to position 3, and set that value to 'd', then I would just do it like this:
if (fileC)
{
while (fgets (line, 200, fileC) != NULL)
{
if (strstr (line, search_string))
{
for (int i = 200 - 1; i >= 3; i--)
{
line[i+1] = line[i];
}
line[3] = 'd';
printf ("%s", line);
fputs (line, stdout);
printf ("%d", LineNumber);
}
LineNumber++;
}
}

Assigning data to 2D array and displaying it C

I am writing a program, that will open csv file and save data to 3D array.
Most of code works pretty good, but I have a problem with assiging records to 2D array.
Here is a code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FILE_MODE "r"
/*
Explode string with given token and assign result to list variable
*/
int explode(const char *src, const char *tokens, char ***list, size_t *len)
{
if(src == NULL || list == NULL || len == NULL) {
return 0;
}
char *str, *copy, **_list = NULL, **tmp;
*list = NULL;
*len = 0;
copy = strdup(src);
if(copy == NULL)
return 1;
str = strtok(copy, tokens);
if(str == NULL) {
goto free_and_exit;
}
_list = realloc(NULL, sizeof *_list);
if(_list == NULL) {
goto free_and_exit;
}
_list[*len] = strdup(str);
if(_list[*len] == NULL)
goto free_and_exit;
(*len)++;
while((str = strtok(NULL, tokens)))
{
tmp = realloc(_list, (sizeof *_list) * (*len + 1));
if(tmp == NULL)
goto free_and_exit;
_list = tmp;
_list[*len] = strdup(str);
if(_list[*len] == NULL)
goto free_and_exit;
(*len)++;
}
free_and_exit:
*list = _list;
free(copy);
return 2;
}
/*
Exploding lines in CSV file
*/
const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ";");
tok && *tok;
tok = strtok(NULL, ";\n"))
{
if (!--num)
return tok;
}
return NULL;
}
int main()
{
FILE *stream;
char fileName[256], table[256], line[256],
**list, **columns, **data;
size_t length;
printf("Witaj uzytkowniku! Podaj nazwe pliku z rozszerzeniem .csv. \n");
scanf("%s", fileName);
explode(fileName, ".", &list, &length);
strcpy(table, list[0]);
stream = fopen("file.csv", FILE_MODE); // not to write path every single time
if (stream == NULL) {
printf("Nie moge otworzyc pliku %s do odczytu!\n", fileName);
exit(1);
}
fgets(line, sizeof line, stream);
explode(line, ";", &columns, &length);
int recordNumber = 0
,columnNumber = 0;
while (fgets(line, sizeof line, stream))
{
char* tmp = strdup(line);
if (getfield(tmp, recordNumber) != NULL) {
columnNumber++;
}
recordNumber++;
free(tmp);
}
fseek(stream, 0, SEEK_SET); // Go to beginning of file
fgets(line, 1024, stream);
int i = 0 // Number of records
,h = 0; // number of columns
char **records[recordNumber][columnNumber];
length = 0;
char *tmp[recordNumber];
// Here I get number of lines and columns in csv file to make 3D array??
while (fgets(line, sizeof line, stream) && i < recordNumber)
{
tmp[i] = strdup(line);
explode(tmp[i], ";", &data, &length);
for (h = 0; h < columnNumber; h++)
{
memcpy(records[i][h], data[h], sizeof(data[h]));
}
i++;
}
for (i = 0; i < recordNumber; i++)
{
for (h = 0; h < columnNumber; h++)
{
printf("%s ", records[i][h][0]);
}
printf("\n");
}
fclose(stream);
return EXIT_SUCCESS;
}
Problem starts, when I try do a loop, that assign data to array:
while (fgets(line, sizeof line, stream) && i < recordNumber)
{
tmp[i] = strdup(line);
explode(tmp[i], ";", &data, &length);
for (h = 0; h < columnNumber; h++)
{
memcpy(records[i][h], data[h], sizeof(data[h]));
}
i++;
}
I tried to use memcpy and strcpy, but none works correctly - I am pretty sure.
When code goes to these lines, there is an error: segmentation fault (core dumping).
All i want to achieve is to fill this array with data from csv file and print it.
Thanks for your help! :)
EDIT:
explode function is not mine. Probably, I found it somewhere on stackoverflow.
When, it comes to the code, after little change, it works
char records[recordNumber][columnNumber][1024];
length = 0;
char *tmp[recordNumber];
while (fgets(line, sizeof line, stream) && i < recordNumber)
{
tmp[i] = strdup(line);
explode(tmp[i], ";", &data, &length);
for (h = 0; h < columnNumber; h++)
{
strcpy(records[i][h], data[h]);
}
i++;
}
Read each line of the file with fgets. strpbrk can be used to find the delimiters. Two pointers can be used to get the number of characters between the delimiters. Then allocate memory and use memcpy to copy the field to the allocated memory.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char ***strpdlm ( char *pdelim, int skip);
char ***freedlm ( char ***ppp);
int main()
{
char ***expld = NULL;
int line = 0;
int field = 0;
//last argument of 1 is skip consecutive delimiters. 0 do not skip
expld = strpdlm ( ";\n", 1);// delimiters semicolon and newline
//print each extracted string
line = 0;
if ( expld) {//not null
while ( expld[line]) {//not null
field = 0;
printf ( "\nfields for line %d\n", line);
while ( expld[line][field]) {//not null
printf ( "expld[%d][%d] %s\n", line, field, expld[line][field]);
field++;
}
line++;
}
}
//free memory and set NULL
expld = freedlm ( expld);
return 0;
}
char ***freedlm ( char ***ppp) {
size_t each = 0;
size_t item = 0;
if ( ppp) {
while ( ppp[each]) {
item = 0;
while ( ppp[each][item]) {
free ( ppp[each][item]);
item++;
}
free ( ppp[each]);
each++;
}
free ( ppp);
}
return NULL;
}
char ***strpdlm ( char *pdelim, int skip) {
char ***xpld = NULL;
char ***temprecord = NULL;
char **tempfield = NULL;
char *pnt = NULL;
char *cur = NULL;
char line[1024] = "";
int span = 0;
int len = 0;
int record = 0;
int field = 0;
FILE *pf = NULL;
if ( ( pf = fopen ( "file.csv", "r")) == NULL) {
perror ( "could not open \"file.csv\"");
return NULL;
}
if ( pdelim) {
while ( fgets ( line, sizeof line, pf)) {
//make sure each line ends with \n
len = strcspn ( line, "\n");
if ( len + 1 < sizeof line) {
line[len] = '\n';
line[len + 1] = '\0';
}
//allocate record + 2 pointers
if ( ( temprecord = realloc ( xpld, ( record + 2) * sizeof ( *xpld))) == NULL) {
fprintf ( stderr, "problem realloc records\n");
fclose ( pf);
return xpld;
}
xpld = temprecord;
xpld[record] = NULL;
field = 0;
cur = line;//cur points to line
while ( ( pnt = strpbrk ( cur, pdelim))) {
if ( pnt != cur || !skip) {
if ( ( tempfield = realloc ( xpld[record], ( field + 2) * sizeof ( **xpld))) == NULL) {
fprintf ( stderr, "problem realloc fields\n");
fclose ( pf);
return xpld;
}
xpld[record] = tempfield;
xpld[record][field] = NULL;
if ( pnt) {
span = pnt - cur;
}
else {
span = strlen ( cur);
}
if ( ( xpld[record][field] = malloc ( span + 1)) == NULL) {
fprintf ( stderr, "problem malloc\n");
fclose ( pf);
return xpld;
}
memcpy ( xpld[record][field], cur, span);
xpld[record][field][span] = '\0';
field++;
xpld[record][field] = NULL;//sentinel NULL
}
cur = pnt + 1;//set cur to point to next field
}
record++;
xpld[record] = NULL;//sentinel NULL
}
}
fclose ( pf);
return xpld;
}

C - Print to console a string that can be deleted

I'm trying to build a program that prints a "default value" an user can quickly change by deleting parts of it and writing again.
The program would print for example:
enter app name: xcode
The user should be able to replace the "xcode" string (but not the ": " part) and then the program should get the entire input.
Is there a way to do it in plain C with the standard console OSX uses?
Thanks a lot
This will place a prompt and default input on the screen. The arrow keys will move the cursor right and left. Mode may be changed from INS (insert) to OVW
(overwrite) using the Ins key. Enter will terminate input as will too many characters. Valid characters may be restricted by using some combination of LETTERS | NUMBERS | DOT | SPACE | SIGN | PUNCT.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#define ESC 27
#define INSERT 50
#define DELETE 51
#define PGUP 53
#define PGDN 54
#define ARROWRIGHT 67
#define ARROWLEFT 68
#define END 70
#define HOME 72
#define OTHER 79
#define BRACKETLEFT 91
#define TILDE 126
#define BACKSPACE 127
#define LETTERS 1
#define NUMBERS 2
#define DOT 4
#define SPACE 8
#define SIGN 16
#define PUNCT 32
#define SIZE 30
static const int STDIN = 0;
typedef struct Field {
int row;//place input on screen row and col
int col;
int contentsize;//allowed length of input
int inputat;//input at this index
int used;//characters used so far
int valid;//limit input to these characters
int insert;//mode insert/overwrite
int promptrow;//place prompt on screen row and col
int promptcol;
int promptsize;
int lastline;
int lastcol;
int stopon;//stop input with this character
char *content;
char *prompt;
} field;
int kbhit(void)
{
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
void prompt ( field *psfield) {
printf ( "\033[%d;%dH", psfield->promptrow, psfield->promptcol);
printf ( "%s", psfield->prompt);
}
int input ( field *psfield) {
int ch = 0;
int to = 0;
printf ( "\033[%d;1H", psfield->lastline);
if ( psfield->insert) {
printf ( "INS");
}
else {
printf ( "OVW");
}
printf ( "\033[%d;%dH", psfield->row, psfield->col);
printf ( "\033[K");//erase to end of line
printf ( "%s", psfield->content);
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
while ( ( ch = getchar ()) != psfield->stopon) {
printf ( "\033[%d;10H", psfield->lastline);
printf ( "\033[K");//erase to end of line
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
if (
( ( psfield->valid & LETTERS && isalpha ( ch)))
|| ( ( psfield->valid & SPACE && ch == ' '))
|| ( ( psfield->valid & DOT && ch == '.'))
|| ( ( psfield->valid & SIGN && ( ch == '+' || ch == '-')))
|| ( ( psfield->valid & NUMBERS && isdigit ( ch)))
|| ( ( psfield->valid & PUNCT && ispunct ( ch)))
) {
if ( psfield->insert && psfield->inputat < psfield->used && psfield->used < psfield->contentsize-3) {
//expand
psfield->used++;
for ( to = psfield->used; to >= psfield->inputat; to--) {
psfield->content[to + 1] = psfield->content[to];
}
printf ( "\033[%d;%dH", psfield->row, psfield->col);
printf ( "\033[K");//erase to end of line
printf ( "%s", psfield->content);
}
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
printf ( "%c", ch);
psfield->content[psfield->inputat] = ch;
psfield->inputat++;
if ( psfield->inputat > psfield->used) {
psfield->used = psfield->inputat;
}
if ( psfield->inputat == psfield->used) {
psfield->content[psfield->inputat] = '\0';
}
if ( psfield->inputat >= psfield->contentsize-1) {
return -1;
}
continue;
}
if ( isprint ( ch)) {
printf ( "\033[%d;10H", psfield->lastline);
printf ( "\033[48;5;124m");//set color white text on red
printf ( "Invalid character");
printf ( "\033[0m");//reset to default colors
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
continue;
}
if ( ch == BACKSPACE) {
if ( psfield->inputat) {
psfield->inputat--;
//contract
for ( to = psfield->inputat; to <= psfield->used; to++) {
psfield->content[to] = psfield->content[to + 1];
}
psfield->used--;
printf ( "\033[%d;%dH", psfield->row, psfield->col);
printf ( "\033[K");//erase to end of line
printf ( "%s", psfield->content);
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
}
}
if ( ch == ESC) {
if ( !kbhit ( )) {
continue;
}
ch = getchar ( );
if ( ch == OTHER) {
ch = getchar ( );
if ( ch == HOME) {
psfield->inputat = 0;
printf ( "\033[%d;%dH", psfield->row, psfield->col);
ch = getchar ( );
}
if ( ch == END) {
psfield->inputat = psfield->used;
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
ch = getchar ( );
}
}
if ( ch == BRACKETLEFT) {
ch = getchar ( );
if ( ch == INSERT) {
ch = getchar ( );
if ( ch == TILDE) {
psfield->insert = !psfield->insert;
printf ( "\033[%d;1H", psfield->lastline);
if ( psfield->insert) {
printf ( "INS");
}
else {
printf ( "OVW");
}
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
}
}
if ( ch == DELETE) {
ch = getchar ( );
if ( ch == TILDE) {
//contract
for ( to = psfield->inputat; to <= psfield->used; to++) {
psfield->content[to] = psfield->content[to + 1];
}
psfield->used--;
printf ( "\033[%d;%dH", psfield->row, psfield->col);
printf ( "\033[K");//erase to end of line
printf ( "%s", psfield->content);
printf ( "\033[%d;%dH", psfield->row, psfield->col + psfield->inputat);
}
}
if ( ch == ARROWRIGHT) {
if ( psfield->inputat < psfield->used) {
printf ( "\033[C");//cursor right
psfield->inputat++;
}
}
if ( ch == ARROWLEFT) {
if ( psfield->inputat) {
printf ( "\033[D");//cursor left
psfield->inputat--;
}
}
}
else {
ungetc ( ch, stdin);
}
}
}
return 0;
}
int main ( ) {
struct termios oldattr, newattr;
struct winsize w;
field sfield = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', NULL, NULL};
//set terminal
tcgetattr( STDIN, &oldattr );
newattr = oldattr;
newattr.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN, TCSANOW, &newattr );
setbuf(stdin, NULL);
//get terminal dimensions
ioctl( 0, TIOCGWINSZ, &w );
sfield.lastline = w.ws_row;
sfield.lastcol = w.ws_col;
printf ( "\033[2J");//clear screen
sfield.row = 5;
sfield.col = 26;
sfield.promptrow = 5;
sfield.promptcol = 1;
sfield.stopon = '\n';//newline will end input
sfield.valid = LETTERS | SPACE | DOT;
sfield.contentsize = 40;//allowed length of input
if ( ( sfield.content = calloc ( sfield.contentsize, 1)) == NULL) {
printf ( "calloc failed\n");
return 1;
}
sfield.prompt = strdup ( "Enter letters or spaces:");
sfield.promptsize = strlen ( sfield.prompt) + 1;
strcpy ( sfield.content, "default");
sfield.used = strlen ( sfield.content);
prompt ( &sfield);
input ( &sfield);
printf ( "\n\ninput was [%s]\n", sfield.content);
printf ( "\n\nbye\n");
free ( sfield.content);
free ( sfield.prompt);
//restore terminal
tcsetattr( STDIN, TCSANOW, &oldattr );
return 0;
}

Resources