How would I fix the alignment on this Table? - c

I have coded this program in C that reads in a file and prints it out to a table that is aligned with vertical bars including a header and footprint. The file always has 3 columns but different amounts of rows. The columns will differ in the amount of characters in each. The problem that I am having is that the first file I read in aligns perfectly but when I read in others that are increased sizes in all of the columns it does not align. Is there a way to make it automatically align or do I have to do this manually every time?
Code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// constant to store the maximum size of the records that can be read from the file
enum
{
// update MAX_SIZE to if the number of rows is more than 1000
MAX_SIZE = 1024
};
// structure to store a record from the file
typedef struct
{
char define[20];
char octal[26];
char description[1000];
} Record;
// string to store the header of the table
char header1[20], header2[20], header3[20];
// function to read the file and return the maximum length of the descriptions read from the file
int readFile(Record rec[], int *size)
{
// open a file for input
FILE *fp = fopen("input2.txt", "r");
// check if the file opened successfully
if (fp == NULL)
{
printf("File could not be opened!");
exit(1);
}
int i = 0;
int maxLength=0;
// read the file
// first we read the header of each column from the file
fscanf(fp, "%s %s %s\n", header1, header2, header3);
// now we read each record from the file
while (fscanf(fp, "%19s ", rec[i].define) == 1)
{
fscanf(fp, "%10s '%[^']'", rec[i].octal, rec[i].description);
// find the length of the description and update the 'maxLength'
if (strlen(rec[i].description) > maxLength)
{
maxLength = strlen(rec[i].description);
}
// increment the value of i
i++;
}
// close the input file
fclose(fp);
// update the number of records read from the file
*size = i;
return maxLength;
}
void printTable(Record rec[], int size, int WIDTH)
{
char p='|';
// print the header of the table
for (int i = 0; i < 22 + WIDTH; i++)
printf("-");
printf("\n| %-7s %c %5s %c %-*s %c\n", header1, p, header2, p, WIDTH, header3,p);
for (int i = 0; i < 22 + WIDTH; i++)
printf("-");
printf("\n");
// print the table data
for (int i = 0; i < size; i++)
printf("| %-7s | %5s | %-*s |\n", rec[i].define, rec[i].octal, WIDTH, rec[i].description);
// print the footer
for (int i = 0; i < 22 + WIDTH; i++)
printf("-");
printf("\n");
}
// driver function
int main()
{
// create an array of recors of MAX_SIZE
Record recs[MAX_SIZE];
// initialize size of recs to zero
int size = 0;
// call readFile() function to read data from the file and update the size of recs
int WIDTH = readFile(recs, &size);
// call printTable() function to print the table in a well-formatted manner
printTable(recs, size, WIDTH);
return 0;
}
File:
#define octal description
O_APPEND 02000 'The file is opened in append mode.'
O_ASYNC 020000 'Enable signal-driven I/O.'
O_CLOEXEC 02000000 'Enable the close-on-exec flag for the new file descriptor.'
O_CREAT 0100 'If pathname does not exist, create it as a regular file.'
O_DIRECT 040000 'Try to minimize cache effects of the I/O to and from this file.'
O_DIRECTORY 0200000 'If pathname is not a directory, cause the open to fail.'
O_DSYNC 010000 'Write operations will complete according to the requirements of synchronized I/O data integrity completion.'
O_EXCL 0200 'Ensure that this call creates the file.'
O_LARGEFILE 0 'Allow files whose sizes cannot be represented in an off_t to be opened.'
O_NOATIME 01000000 'Do not update the file last access time (st_atime in the inode) when the file is read(2).'
O_NOCTTY 0400 'If pathname refers to a terminal device it will not become the processs controlling terminal.'
O_NOFOLLOW 0400000 'If pathname is a symbolic link, then the open fails, with the error ELOOP.'
O_NONBLOCK 04000 'When possible, the file is opened in nonblocking mode.'
O_PATH 010000000 'Obtain a file descriptor that can be used perform operations that act purely at the file descriptor level.'
O_SYNC 04010000 'Write operations will complete according to the requirements of synchronized I/O file integrity completion.'
O_TMPFILE 020200000 'Create an unnamed temporary regular file.'
O_TRUNC 01000 'If the file already exists and is a regular file it will be truncated to length 0.'
What is currently being printed:
---------------------------------------------------------------------------------------------------------------------------------
| #define | octal | description |
---------------------------------------------------------------------------------------------------------------------------------
| O_APPEND | 02000 | The file is opened in append mode. |
| O_ASYNC | 020000 | Enable signal-driven I/O. |
| O_CLOEXEC | 02000000 | Enable the close-on-exec flag for the new file descriptor. |
| O_CREAT | 0100 | If pathname does not exist, create it as a regular file. |
| O_DIRECT | 040000 | Try to minimize cache effects of the I/O to and from this file. |
| O_DIRECTORY | 0200000 | If pathname is not a directory, cause the open to fail. |
| O_DSYNC | 010000 | Write operations will complete according to the requirements of synchronized I/O data integrity completion. |
| O_EXCL | 0200 | Ensure that this call creates the file. |
| O_LARGEFILE | 0 | Allow files whose sizes cannot be represented in an off_t to be opened. |
| O_NOATIME | 01000000 | Do not update the file last access time (st_atime in the inode) when the file is read(2). |
| O_NOCTTY | 0400 | If pathname refers to a terminal device it will not become the processs controlling terminal. |
| O_NOFOLLOW | 0400000 | If pathname is a symbolic link, then the open fails, with the error ELOOP. |
| O_NONBLOCK | 04000 | When possible, the file is opened in nonblocking mode. |
| O_PATH | 010000000 | Obtain a file descriptor that can be used perform operations that act purely at the file descriptor level. |
| O_SYNC | 04010000 | Write operations will complete according to the requirements of synchronized I/O file integrity completion. |
| O_TMPFILE | 020200000 | Create an unnamed temporary regular file. |
| O_TRUNC | 01000 | If the file already exists and is a regular file it will be truncated to length 0. |
---------------------------------------------------------------------------------------------------------------------------------
What it should look like:
-----------------------------------------------------------------------------------------------------------------------------------------
| #define | octal | description |
-----------------------------------------------------------------------------------------------------------------------------------------
| O_APPEND | 02000 | The file is opened in append mode. |
| O_ASYNC | 020000 | Enable signal-driven I/O. |
| O_CLOEXEC | 02000000 | Enable the close-on-exec flag for the new file descriptor. |
| O_CREAT | 0100 | If pathname does not exist, create it as a regular file. |
| O_DIRECT | 040000 | Try to minimize cache effects of the I/O to and from this file. |
| O_DIRECTORY | 0200000 | If pathname is not a directory, cause the open to fail. |
| O_DSYNC | 010000 | Write operations will complete according to the requirements of synchronized I/O data integrity completion. |
| O_EXCL | 0200 | Ensure that this call creates the file. |
| O_LARGEFILE | 0 | Allow files whose sizes cannot be represented in an off_t to be opened. |
| O_NOATIME | 01000000 | Do not update the file last access time (st_atime in the inode) when the file is read(2). |
| O_NOCTTY | 0400 | If pathname refers to a terminal device it will not become the processs controlling terminal. |
| O_NOFOLLOW | 0400000 | If pathname is a symbolic link, then the open fails, with the error ELOOP. |
| O_NONBLOCK | 04000 | When possible, the file is opened in nonblocking mode. |
| O_PATH | 010000000 | Obtain a file descriptor that can be used perform operations that act purely at the file descriptor level. |
| O_SYNC | 04010000 | Write operations will complete according to the requirements of synchronized I/O file integrity completion. |
| O_TMPFILE | 020200000 | Create an unnamed temporary regular file. |
| O_TRUNC | 01000 | If the file already exists and is a regular file it will be truncated to length 0. |
-----------------------------------------------------------------------------------------------------------------------------------------

Example function.
struct a
{
char *s ; int x; char *y;
} a[] = {
{"Hello", 435342435432, "1"},
{"dfgsfdgdgdfgdf", 5, "1fdsfsdfs"},
{"Hellodfds", 43534, "sdffs"},
{"H", 2435432, "1dfdsfdsfsdd"},
{NULL,}
};
void print(struct a *data)
{
int widths[3] = {0};
struct a *wrk;
size_t len;
for(wrk = data; wrk -> s; wrk++)
{
if((len = strlen(wrk -> s)) > widths[0]) widths[0] = len;
if((len = strlen(wrk -> y)) > widths[2]) widths[2] = len;
if((len = snprintf(NULL, 0, "%d", wrk -> x)) > widths[1]) widths[1] = len;
}
for(wrk = data; wrk -> s; wrk++)
{
printf("| %-*s | %*d | %*s |\n", widths[0], wrk -> s , widths[1], wrk -> x, widths[2], wrk -> y);
}
}
Output:
| Hello | 1550738536 | 1 |
| dfgsfdgdgdfgdf | 5 | 1fdsfsdfs |
| Hellodfds | 43534 | sdffs |
| H | 2435432 | 1dfdsfdsfsdd |

Consider a contrived example of accomplishing the same goal.
#include <stdio.h>
#include <string.h>
struct ContrivedData {
char a[100];
char b[100];
char c[100];
};
int main(void) {
struct ContrivedData cd1 = {"Hello", "world", "!"};
struct ContrivedData cd2 = {"foo", "bar", "baz"};
struct ContrivedData cd[2];
cd[0] = cd1;
cd[1] = cd2;
int cd_len = sizeof(cd) / sizeof(*cd);
int max_a_len = 0;
int max_b_len = 0;
int max_c_len = 0;
for (int i = 0; i < cd_len; i++) {
int a_len = strlen(cd[i].a);
if (a_len > max_a_len) {
max_a_len = a_len;
}
int b_len = strlen(cd[i].b);
if (b_len > max_b_len) {
max_b_len = b_len;
}
int c_len = strlen(cd[i].c);
if (c_len > max_c_len) {
max_c_len = c_len;
}
}
for (int i = 0; i < cd_len; i++) {
printf("%-*s | %-*s | %-*s\n",
max_a_len, cd[i].a,
max_b_len, cd[i].b,
max_c_len, cd[i].c);
}
return 0;
}
Before printing the data I iterate over the array and calculate the maximum width of each field. Depending on the type of data, you may need to use some function other than strlen.
The result I get is:
% ./test2
Hello | world | !
foo | bar | baz
If I change the data a bit, you can see that it still stays aligned.
% ./test2
Hello | world | !
foo | barbarbar | baz

Related

What is the limit of file size in ftruncate in OSX?

I am trying to call ftruncate in OSX (10.14.5) and (10.14.4) as below:
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, const char *argv[]) {
off_t len;
FILE *fp;
int ret;
if (argc < 3) {
fprintf( stderr, "Usage:\n$0 filename length\n" );
exit(-1);
}
fp = fopen(argv[1], "a+");
if (!fp) {
fprintf(stderr, "Couldn't open %s: %s\n",
argv[1], strerror(errno));
exit(-1);
}
len = (off_t) atoll(argv[2]);
uint64_t m = 1ULL << len;
printf("%lld\n", m/(1024*1024*1024));
errno = 0;
ret = ftruncate(fileno(fp), m);
if (ret != 0) {
fprintf(stderr, "Couldn't truncate(\"%s\",%llu): %s\n",
argv[1], len, strerror(errno));
}
fclose(fp);
exit(ret);
}
I have 100G left in the filesystem. The issue is that ftruncate succeeds with values that I do not understand, and fails with values I do not understand.
I get surprising values, sometimes failing and succeeding for same size. Here is a typical run on a machine with OSX (10.14.4).
| ./alloc x 42
4096.000000
Couldn't truncate("x",42): No space left on device
| ./alloc x 41
2048.000000
| ./alloc x 42
4096.000000
| du -sh x
4.0T x
| rm x
| ./alloc x 42
4096.000000
Couldn't truncate("x",42): No space left on device
| du -sh x
0B x
| ./alloc x 42
4096.000000
Couldn't truncate("x",42): No space left on device
| du -sh x
0B x
| ./alloc x 41
2048.000000
| du -sh x
2.0T x
| ./alloc x 40
1024.000000
| du -sh x
0B x
On another with OSX (10.14.5) I do not see the size after creation at all, with similarly surprising values, sometimes failing and succeeding for same size.
| ./alloc x 41
2048.000000
Couldn't truncate("x",41): No space left on device
zsh: exit 255 ./alloc x 41
| ./alloc x 40
1024.000000
| du -sh x
0B x
| rm x
| ./alloc x 40
1024.000000
Couldn't truncate("x",40): No space left on device
zsh: exit 255 ./alloc x 40
| du -sh x
0B x
| ./alloc x 39
512.000000
| du -sh x
0B x
What is happening here? and what is the actual limit for ftruncate in OSX?
Note that unlike in the linked answer, I am not asking whether ftruncate actually copies data. My question is why there are so different results in different consecutive runs, and specifically in the OSX machines I have it seems to behave differently in both machines. If it is not related to the filesystem, why does it fail on somewhat different values in different systems?

Redirection out using open

Im making a shell and working on output redirection, specifically appending to files. Problem is, the following code always overwrites the contents of the file and does not simply append.
int val = -1;
//Flag issue?
val = open(destination, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
if (val != -1) {
close(1);
dup(val);
close(val);
}

Very poor file system performance

I have a function that basically does this:
int mmkdir(const char *path, mode_t mode)
{
struct stat st;
if (stat(path, &st) < 0)
{
if (errno != ENOENT)
return -1;
if (mkdir(path, S_IWUSR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0 && errno != EEXIST)
return -1;
}
else if (!S_ISDIR(st.st_mode))
{
errno = ENOTDIR;
return -1;
}
return 0;
}
int fun(int id, int id2)
{
time_t ts;
struct tm timeinfo;
char buff[1024], buff1[20], buff2[20], buff3[20];
ts = time(NULL);
localtime_r(&ts, &timeinfo);
strftime(buff1, sizeof(buff1), "%Y%m%d", &timeinfo);
strftime(buff2, sizeof(buff2), "%H", &timeinfo);
snprintf(buff, sizeof(buff), "%s/%s", dir, buff1);
if (mmkdir(buff, ORDER_FILE_DEFAULT_PERMS) < 0)
return -1;
len = strlen(buff);
snprintf(buff + len, sizeof(buff) - len, "/%s", buff2);
if (mmkdir(buff, ORDER_FILE_DEFAULT_PERMS) < 0)
return -1;
len += strlen(buff2) + 1;
strftime(buff3, sizeof(buff2), "%M%S", &timeinfo);
snprintf(buff + len, sizeof(buff) - len - 1, "/%010d-%04d-%s%s.%s",
id, id2, buff2, buff3, ext);
return open(buff, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
}
Plese don't check for errors, it's a working code. It basically calls stat(2), mkdir(2) (sometimes) and open(2).
The problem is that when to I/O load on the server is pretty high, this piece of code sometimes takes even 7s (!!) to complete.
These files that this functions create are located in a folder in /, which is mounted:
/dev/md0 on / type ext4 (rw,errors=remount-ro)
and can be up to 1000 files in a single folder.
What may be the problem? Why this may take so long? Is there any misconfiguration?
I don't ask only for improvements in the code, but in the server configuration also, if possible.
As per request in the comments, the output of cat /proc/mdstat is:
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md3 : active raid1 sdd1[1] sdc1[0]
488282000 blocks super 1.2 [2/2] [UU]
md1 : active raid1 sda2[0] sdb2[1]
15624120 blocks super 1.2 [2/2] [UU]
md2 : active raid1 sda3[0] sdb3[1]
1958900 blocks super 1.2 [2/2] [UU]
md0 : active raid1 sda1[0] sdb1[1]
470798200 blocks super 1.2 [2/2] [UU]
that means that the disks are ok
If this function is called substantially more than once per hour, and the folders are not deleted, then your mmkdir calls are redundant. I would implement some kind of caching scheme where you remember the last hour in which you created a folder, and skip creating a new folder if you already created it. This will remove two stat calls, which could make a big difference on an overloaded system.
There's likely to be no further improvement you can make to the code alone, since the open call would be the only remaining system call, and it cannot be elided without changing the meaning of the function.

C - write() not writing to file

My problem is simple, when i try to confirm if the function wrote on the file, nothing shows up, the file is there, but there's nothing inside the file, where should be 1024 times the string i wanted.
int escreve1x( const char* path , const char* cadeia )
int fd = open( path, O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH );
int i;
printf("%s\n", cadeia);
for ( i=0 ; i<=1024 ; i++ )
{
write( fd, cadeia, 10);
}
return 0 ;
1-Add "O_RDWR" flag for making fd writable.
2-Always debug the result of write syscall;
int fd = open( path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH );
if(fd<0) {
printf("Open failed\n");
return 1;
}
int i;
printf("%s\n", cadeia);
for ( i=0 ; i<=1024 ; i++ ) {
int status=write( fd, cadeia, 10);
if(status<0) {
printf("Write failed");
}
}
return 0;
If it says write has failed then check errno.

Redirection doesn't work in shell:: ls: cannot access >: No such file or directory

I don't know why redirection doesn't work in the shell I have written. Here's my code"
int i;
for (i=1; !args[i];i++)
{
if (args[i]== ">")
{
printf("argv[i] %s %d \n", args[i], i);
int out;
// out = open("out", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
out=open("out", O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU);
int fdl=dup2(out,1);
close(out);
execvp(args[0],args);
}
}
Also here's the error I receive :
mysh> ls
basic_shell basic_shell.c~ fork fork_2 fork_cp.c
basic_shell.c basic_shell_OK.c fork_1 fork.c
mysh> ls > file
ls: cannot access >: No such file or directory
ls: cannot access file: No such file or directory
Please let me know what's wrong?
If args is an array of char*, then this condition
if (args[i]== ">")
does not do what you think it does. It compares the pointers and not what they point to. To compare string you have to use strcmp.

Resources