I'm working at a simple FTP-Server (just for fun) and the last step is to store a file with the "STOR" cmd.
rec_file method:
int rec_file(char *filename, int sockfd){
int bytes_read;
char buffer[4096];
FILE *f = fopen(filename, "wb");
while (bytes_read=read(sockfd,buffer,sizeof(buffer))){
fwrite(buffer , 1 , sizeof(buffer) , f);
}
fclose(f);
return 0;
}
Test File a.txt:
TEST123
456
789
TEST!!
sent file a.txt:
TEST123
456
789
TEST!! AÛD Ìk P ™sB ÃB p Àa ðÿÿÿÿÿÿ P # €Ìk Ìk # dB % 0 % Øa P 0 | w n [ Ìk 8Y
ý % 8Y
ý # Àk W.B G
ý 8Y
ý QH /home/felix/ftp ¨A PQ
ý Ãk R
ý `Q
ý =F ) -rA ÿÿÿÿÿÿÿÿ Çk ¨ * 0k 1„A Çk -rA ßJI Çk ¨ 0k 1„A Çk ¨
So what am I doing wrong?
Your code may write more bytes to the file than you have received from the socket.
The return value of read which gets stored in bytes_read will tell you how many bytes have actually been read. Even if the amount of data is large, read may not always read a full buffer, it may return a smaller number. You should also handle negative values as errors.
The code below has a very simple error handling. In a real application you might have to retry the read call on certain errno values instead of stopping to read data.
while ((bytes_read=read(sockfd,buffer,sizeof(buffer))) > 0){
fwrite(buffer , 1 , bytes_read, f);
}
if(bytes_read < 0) {
perror("read failed");
/* maybe other error handling */
}
Related
I have the following certificate:
-----BEGIN CERTIFICATE-----
MIIDWjCCAkKgAwIBAgIVAJ3wzBnLSnQvYi31rNVQRAXDUO/zMA0GCSqGSIb3DQEB
CwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t
IEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0yMDA3MjgxMTMz
MTJaFw00OTEyMzEyMzU5NTlaMB4xHDAaBgNVBAMME0FXUyBJb1QgQ2VydGlmaWNh
dGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHc2tmezGoekLjkQlb
+YOBKFyPswYR+GLq/JRVbFX2k4OrHF5js4GTfbHm1oQ733KbcnIugdejtQnRhtnr
1HRk3pqedVhRKGRo2DFDYyuX3K1UR6xna1poJF+6WNy6vXGxIQYKi7SNS5LtzkRT
1FCziOLBaxfcCRNgR1NBHjlcFsUWyL4evMok6h/wU7HA3/dfKEisyLdh3sMy7Yox
Im/ldvyX+9pH7Hj0TrGGTd5f8GtX8npNuSKdkntuag95r+vAaAPp6bQVyPWm8T/G
SUN8N7Nvc9DOcJ8ZhvB/Ubq+Fa/eoUnr3SgXInufLHhrfxJW7dyrBTlw/1kdXgYw
YiKnAgMBAAGjYDBeMB8GA1UdIwQYMBaAFP4UzdqnzQ4l89+D7UhXC5MKWnOJMB0G
A1UdDgQWBBSn95OHFqTn3DrE3anpNq5RoOsT+DAMBgNVHRMBAf8EAjAAMA4GA1Ud
DwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEA2Hvrxy2N0xt3I/w/7JIyoTH4
ixUKMaD1QXe+g6LrsQSCVVsaq0L468OpyydVzQLQONXvDDRv3rqIEel1hPAJNG0y
dp3g+WC1dPl7E44btM+59gBf1369lFwV6FbJMwCltVBUJ4hFAjt3QTkWRHq6DlFQ
wa896aSr5UUiVNAJjf/hLVjERlVG4wDjPN7YifQssRqlNcYDgok3UhVsBfKIGnct
WFbisX+0ONMyNnE1Qq6bX5g4sLN7VlwFhADiz1Xp2rUtLECR1NSPutYibWyvJJ8d
htYYV1a0FSkg7JKyvOIJ8IYKEPsKE+UYo1Z8DwkmHHcap+h0OMWAnKQgRXn6QQ==
-----END CERTIFICATE-----
I fed this into several certificate reading sites, and they were all able to parse and display its contents.
I tried using mbedtls to parse this certificate using the following code:
mbedtls_x509_crt certificate;
mbedtls_x509_crt_init(&certificate);
char certificate_string[] = "-----BEGIN CERTIFICATE--..."
int result_code = mbedtls_x509_crt_parse(&certificate, (unsigned char*)certificate_string, strlen(certificate_string));
if(result_code != 0) {
char err_str[256];
mbedtls_strerror(result_code, err_str, 256);
printf("Could not read the certificate. Error: %s\n", err_str);
return -1;
}
I then check the result_code for 0, and print the error message if it is not. I get the following error message every time I try to parse this certificate:
"Could not read the certificate. Error: X509 - The CRT/CRL/CSR format is invalid, e.g. different type expected"
I tried looking at the mbedtls_x509_crt_parse code to see what causes this message, and I then modified the code to use the following pieces of mbedtls_x509_crt_parse instead:
mbedtls_pem_context pem;
size_t use_len;
mbedtls_pem_init(&pem);
// If we get there, we know the string is null-terminated
int ret = mbedtls_pem_read_buffer(&pem,
"-----BEGIN CERTIFICATE-----",
"-----END CERTIFICATE-----",
(unsigned char *)certificate_string,
NULL,
0,
&use_len);
if(ret != 0) {
printf("we could not pem read the string\n");
return -1;
}
else {
printf("We pem read the certificate\n");
}
ret = mbedtls_x509_crt_parse_der(&certificate, pem.buf, pem.buflen);
if(ret != 0) {
printf("crt parse der has failed\n");
}
else {
printf("The issuer is: %s\n", certificate.issuer.val.p);
return 0;
}
When I run the program, I get the following output:
491231235959Z010�Uzon Web Services O=Amazon.com Inc. L=Seattle ST=Washington C=US0
*�H�� AWS IoT Certificate0�"0
I kept searching for answers as to what may be wrong, and I found a post saying that mbedtls is configured by default to use RSA 1024, so if your key is 2048 (and it is in mine) then mbedtls will have an error with parsing. I modified the configuration file to use 2048 and I rebuilt the library, but I still get errors.
Any ideas? I feel like I am really close, because mbedtls_x509_crt_parse executes almost the whole way through. I am pretty sure I am using the library correctly based on code samples I have seen.
Thanks!
Initially, the PEM format certificate string was parsed with the following code:
mbedtls_x509_crt certificate;
mbedtls_x509_crt_init(&certificate);
char certificate_string[] = "-----BEGIN CERTIFICATE--..."; // actually much longer
int result_code = mbedtls_x509_crt_parse(&certificate, (unsigned char*)certificate_string, strlen(certificate_string));
That resulted in a parsing error because for PEM format input, the final argument of the call to mbedtls_x509_crt certificate should be the length of the input including the null terminator. Changing the final argument to 1 + strlen(certificate_string) fixes the issue.
After successfully parsing, the issuer string was printed using:
printf("The issuer is: %s\n", certificate.issuer.val.p);
That produced some junk output that looked as if the initial part of the issuer string had been overwritten, but was actually due to the lack of a null terminator in the issuer string. The bytes of data after the issuer string included ASCII CR characters causing the terminal cursor position to move to the start of the line and print over the initial part of the output. (The CR characters can be seen by piping the output through | od -c for example, wherewith they are displayed as \r.)
Piping the output through | od -c produces:
0000000 T h e i s s u e r i s : A
0000020 m a z o n W e b S e r v i c
0000040 e s O = A m a z o n . c o m
0000060 I n c . L = S e a t t l e S
0000100 T = W a s h i n g t o n C = U
0000120 S 0 036 027 \r 2 0 0 7 2 8 1 1 3 3 1
0000140 2 Z 027 \r 4 9 1 2 3 1 2 3 5 9 5 9
0000160 Z 0 036 1 034 0 032 006 003 U 004 003 \f 023 A W
0000200 S I o T C e r t i f i c a t
0000220 e 0 202 001 " 0 \r 006 \t * 206 H 206 367 \r 001
0000240 001 001 005 \n
0000244
That shows unprintable bytes as 3-digit octal codes or as C backslash escape codes, depending on the byte value.
To print the issuer string without the junk, change the printf call to the following:
printf("The issuer is: %.*s\n", (int)certificate.issuer.val.len, certificate.issuer.val.p);
I'm attempting to recreate the wc command in c and having issues getting the proper number of words in any file containing machine code (core files or compiled c). The number of logged words always comes up around 90% short of the amount returned by wc.
For reference here is the project info
Compile statement
gcc -ggdb wordCount.c -o wordCount -std=c99
wordCount.c
/*
* Author(s) - Colin McGrath
* Description - Lab 3 - WC LINUX
* Date - January 28, 2015
*/
#include<stdio.h>
#include<string.h>
#include<dirent.h>
#include<sys/stat.h>
#include<ctype.h>
struct counterStruct {
int newlines;
int words;
int bt;
};
typedef struct counterStruct ct;
ct totals = {0};
struct stat st;
void wc(ct counter, char *arg)
{
printf("%6lu %6lu %6lu %s\n", counter.newlines, counter.words, counter.bt, arg);
}
void process(char *arg)
{
lstat(arg, &st);
if (S_ISDIR(st.st_mode))
{
char message[4056] = "wc: ";
strcat(message, arg);
strcat(message, ": Is a directory\n");
printf(message);
ct counter = {0};
wc(counter, arg);
}
else if (S_ISREG(st.st_mode))
{
FILE *file;
file = fopen(arg, "r");
ct currentCount = {0};
if (file != NULL)
{
char holder[65536];
while (fgets(holder, 65536, file) != NULL)
{
totals.newlines++;
currentCount.newlines++;
int c = 0;
for (int i=0; i<strlen(holder); i++)
{
if (isspace(holder[i]))
{
if (c != 0)
{
totals.words++;
currentCount.words++;
c = 0;
}
}
else
c = 1;
}
}
}
currentCount.bt = st.st_size;
totals.bt = totals.bt + st.st_size;
wc(currentCount, arg);
}
}
int main(int argc, char *argv[])
{
if (argc > 1)
{
for (int i=1; i<argc; i++)
{
//printf("%s\n", argv[i]);
process(argv[i]);
}
}
wc(totals, "total");
return 0;
}
Sample wc output:
135 742 360448 /home/cpmcgrat/53/labs/lab-2/core.22321
231 1189 192512 /home/cpmcgrat/53/labs/lab-2/core.26554
5372 40960 365441 /home/cpmcgrat/53/labs/lab-2/file
24 224 12494 /home/cpmcgrat/53/labs/lab-2/frequency
45 116 869 /home/cpmcgrat/53/labs/lab-2/frequency.c
5372 40960 365441 /home/cpmcgrat/53/labs/lab-2/lineIn
12 50 1013 /home/cpmcgrat/53/labs/lab-2/lineIn2
0 0 0 /home/cpmcgrat/53/labs/lab-2/lineOut
39 247 11225 /home/cpmcgrat/53/labs/lab-2/parseURL
138 318 2151 /home/cpmcgrat/53/labs/lab-2/parseURL.c
41 230 10942 /home/cpmcgrat/53/labs/lab-2/roman
66 162 1164 /home/cpmcgrat/53/labs/lab-2/roman.c
13 13 83 /home/cpmcgrat/53/labs/lab-2/romanIn
13 39 169 /home/cpmcgrat/53/labs/lab-2/romanOut
7 6 287 /home/cpmcgrat/53/labs/lab-2/URLs
11508 85256 1324239 total
Sample rebuild output (./wordCount):
139 76 360448 /home/cpmcgrat/53/labs/lab-2/core.22321
233 493 192512 /home/cpmcgrat/53/labs/lab-2/core.26554
5372 40960 365441 /home/cpmcgrat/53/labs/lab-2/file
25 3 12494 /home/cpmcgrat/53/labs/lab-2/frequency
45 116 869 /home/cpmcgrat/53/labs/lab-2/frequency.c
5372 40960 365441 /home/cpmcgrat/53/labs/lab-2/lineIn
12 50 1013 /home/cpmcgrat/53/labs/lab-2/lineIn2
0 0 0 /home/cpmcgrat/53/labs/lab-2/lineOut
40 6 11225 /home/cpmcgrat/53/labs/lab-2/parseURL
138 318 2151 /home/cpmcgrat/53/labs/lab-2/parseURL.c
42 3 10942 /home/cpmcgrat/53/labs/lab-2/roman
66 162 1164 /home/cpmcgrat/53/labs/lab-2/roman.c
13 13 83 /home/cpmcgrat/53/labs/lab-2/romanIn
13 39 169 /home/cpmcgrat/53/labs/lab-2/romanOut
7 6 287 /home/cpmcgrat/53/labs/lab-2/URLs
11517 83205 1324239 total
Notice the difference in the word count (second int) from the first two files (core files) as well as the roman file and parseURL files (machine code, no extension).
C strings do not store their length. They are terminated by a single NUL (0) byte.
Consequently, strlen needs to scan the entire string, character by character, until it reaches the NUL. That makes this:
for (int i=0; i<strlen(holder); i++)
desperately inefficient: for every character in holder, it needs to count all the characters in holder in order to test whether i is still in range. That transforms a simple linear Θ(N) algorithm into an Θ(N2) cycle-burner.
But in this case, it also produces the wrong result, since binary files typically include lots of NUL characters. Since strlen will actually tell you where the first NUL is, rather than how long the "line" is, you'll end up skipping a lot of bytes in the file. (On the bright side, that makes the scan quadratically faster, but computing the wrong result more rapidly is not really a win.)
You cannot use fgets to read binary files because the fgets interface doesn't tell you how much it read. You can use the Posix 2008 getline interface instead, or you can do binary input with fread, which is more efficient but will force you to count newlines yourself. (Not the worst thing in the world; you seem to be getting that count wrong, too.)
Or, of course, you could read the file one character at a time with fgetc. For a school exercise, that's not a bad solution; the resulting code is easy to write and understand, and typical implementations of fgetc are more efficient than the FUD would indicate.
I'm trying to generate a data file and to plot it with Gnuplot. The problem is when I keep my Nstep lower than 348 I get the error
line 0: warning: Skipping data file with no valid points
plot 'plot.txt' using 1:2 with lines
^
line 0: x range is invalid
But I keep the Nstep higher than 348 everything works fine. I do not understand why. Here is my C code:
int main(void){
int Nstep = 348;
//omitted part...
FILE *pipe = fopen("plot.txt", "w+");
while (n<Nstep) {
pos[n+1] = pos[n] + v[n]*h;
v[n+1] = v[n] + h * Fx(pos[n]);
fprintf(pipe, "%d %05.3lf\n", n, v[n]);
n++;
}
close(pipe);
system("gnuplot -p -e \"plot 'plot.txt' using 1:2 with lines\"");
return 0;
}
plot.txt example (Nstep = 10)
1 100.000
2 99.000
3 97.000
4 94.010
5 90.050
6 85.150
7 79.349
8 72.697
9 65.252
10 57.079
I am unable to replicate your error as you didn't include the full source (function Fx and definitions of pos and v). You are calling the wrong close. You should call fclose() (this will flush the file handle too).
fclose(pipe)
And not
close(pipe)
You could explicitly flush the data by calling fflush().
I am writing a c program that opens a txt file and want to read the last line of the txt file.
I am not that proficient in C so bear in mind that I may not know all of the concepts in C. I am stuck at the part where I use fscanf to read all the lines of my txt file but I want to take the last line of the txt file and get the values as described below.
Here is my incomplete code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE *sync;
void check()
{
int success; //to hold the results if the timestamps match
sync = fopen("database.txt","r");
char file[] = "database.txt";
while (fscanf(sync, "%d.%06d", &file) != EOF)
{
}
fclose(sync);
}
sample txt file:
/////// / //// ///// ///// //////////////// Time: 1385144574.787665 //////// /
/////// / //// ///// ///// //////////////// Time: 1385144574.787727 //////// /
/////// / //// ///// ///// //////////////// Time: 1385144574.787738 //////// /
/////// / //// ///// ///// //////////////// Time: 1385144574.787746 //////// /
/////// / //// ///// ///// //////////////// Time: 1385144574.787753 //////// /
The / are some words, symbols and numbers I do not want, just the numbers in sample txt as shown above
I appreciate any examples and pointing out errors I made so I can understand this much better.
Since I made some people confused about the text file, here is what it really is. This is the format it will be so I should know the length of each line. However, I will not be able to know how many lines there will be as it may be updated.
Socket: 0 PGN: 65308 Data: 381f008300000000 Time: 1385144574.787925 Address: 28
Socket: 0 PGN: 65398 Data: 0000000100000000 Time: 1385144574.787932 Address: 118
Socket: 0 PGN: 61444 Data: f07d83351f00ffff Time: 1385144574.787940 Address: 4
Socket: 0 PGN: 65266 Data: 260000000000ffff Time: 1385144574.787947 Address: 242
Socket: 0 PGN: 65309 Data: 2600494678fff33c Time: 1385144574.787956 Address: 29
Socket: 0 PGN: 65398 Data: 0000000100000000 Time: 1385144574.787963 Address: 118
Socket: 0 PGN: 61444 Data: f07d833d1f00ffff Time: 1385144574.787971 Address: 4
Socket: 0 PGN: 65398 Data: 0000000100000000 Time: 1385144574.787978 Address: 118
Socket: 0 PGN: 61443 Data: d1000600ffffffff Time: 1385144574.787985 Address: 3
Socket: 0 PGN: 65308 Data: 451f008300000000 Time: 1385144574.787993 Address: 28
Socket: 0 PGN: 65317 Data: e703000000000000 Time: 1385144574.788001 Address: 37
Again I am after the Time values (eg. 1385144574.787925) at the last line of the txt file.
Hope this helps.
Since you're after the last line of the file, and you didn't mention how large the file might be, it could be worth while to start reading the file from the end, and work your way backwards from there:
FILE *fp = fopen("database.txt", "r");
fseek(fp, 0, SEEK_END);//sets fp to the very end of your file
From there, you can use fseek(fp, -x, SEEK_CUR); where x is the number of bytes you want to go back, until you get to where you want... other than that, Jekyll's answer should work just fine.
However, to get the last line, I tend to do something like this:
FILE *fp = fopen("database.txt", "r");
char line[1024] = "";
char c;
int len = 0;
if (fp == NULL) exit (EXIT_FAILURE);
fseek(fp, -1, SEEK_END);//next to last char, last is EOF
c = fgetc(fp);
while(c == '\n')//define macro EOL
{
fseek(fp, -2, SEEK_CUR);
c = fgetc(fp);
}
while(c != '\n')
{
fseek(fp, -2, SEEK_CUR);
++len;
c = fgetc(fp);
}
fseek(fp, 1, SEEK_CUR);
if (fgets(line, len, fp) != NULL) puts(line);
else printf("Error\n");
fclose(fp);
The reasoning behind my len var is so that I can allocate enough memory to accomodate the entire line. Using an array of 1024 chars should suffice, but if you want to play it safe:
char *line = NULL;
//read line
line = calloc(len+1, sizeof(char));
if (line == NULL)
{
fclose(fp);
exit( EXIT_FAILURE);
}
//add:
free(line);//this line!
fclose(fp);
Once you've gotten that line, you can use Jekyll's sscanf examples to determine the best way to extract whatever you want from that line.
The way you are using fscanf is wrong as the actual vector of arguments needs to match what you are collecting (as you can see in the manpage). Instead of using fscanf you may consider using fgets and then filtering for what you are looking for in the latest raw with a regex through sscanf.
Note:: I collected the value in double format, you may choose the format that suits you the most for your problem (string?int.int?float?), in order to do this you should check for regex using scanf. Please come back if you cannot accomplish this task.
update:: due to some requests I wrote some few examples of different pattern matching. These should be a good starting point to fix your problems.
update::
1. I have seen that you added the pattern of your db file so we can now state that both #3 and #4 match and put the 3 here (faster).
2. I removed the feof check as for your request, but note that the check is fine if you know what you are doing. Basically you have to keep in mind that stream's internal position indicator may point to the end-of-file for the next operation, but still, the end-of-file indicator may not be set until an operation attempts to read at that point.
3. You asked to remove the char line[1024]={0,}; This instruction is used to initialize the line[1024] array which will contain the lines that you read from the file. This is needed! To know what that instruction is please see here
Code:
void check()
{
char line[1024]={0,}; // Initialize memory! You have to do this (as for your question)
int n2=0;
int n3=0;
sync = fopen("database.txt", "r");
if( sync ) {
while( fgets(line, 1024, sync) !=NULL ) {
// Just search for the latest line, do nothing in the loop
}
printf("Last line %s\n", line); //<this is just a log... you can remove it
fclose(sync);
// This will look for Time and it will discard it collecting the number you are looking for in n2 and n3
if (sscanf(line, "%*[^T]Time: %d.%d", &n2, &n3) ) {
printf( "%d.%d\n", n2, n3);
}
}
}
Example 2
if for instance you need to collect the value using two integers you will need to replace the sscanf of the example above with the following code:
unsigned int n2, n3;
if (sscanf(line, "%*[^0-9]%d.%d", &n2, &n3) ) {
printf( "%d.%d\n", n2, n3);
}
said this you should figure out how to collect other formats.
Example 3
A better regex. In case there are others number in the file before the giving pattern you may want to match on Time, so let's say that there isn't any T before. A regex for this can be:
if (sscanf(line, "%*[^T]Time: %d.%d", &n2, &n3) ) {
printf( "%d.%d\n", n2, n3);
}
The regex using sscanf can be not suitable for your pattern, in that case you need to consider the usage of gnu regex library or you can mix strstr and sscanf like I did in the following example.
Example 4
This can be useful if you don't find a common pattern. In that case you may want to trigger on the string "Time" using strstr before calling the sscanf
char *ptr = strstr( line, "Time:" );
if( ptr != NULL ) {
if (sscanf(ptr, "%*[^0-9]%d.%d", &n2, &n3) ) {
printf( "%d.%d\n", n2, n3);
}
}
* Note *
You may need to find your way to parse the file and those above can be only suggestions because you may have more specific or different patterns in your file but the instruction I posted here should be enough to give you the instruments to do the job in that case
I'm doing a project on filesystems on a university operating systems course, my C program should simulate a simple filesystem in a human-readable file, so the file should be based on lines, a line will be a "sector". I've learned, that lines must be of the same length to be overwritten, so I'll pad them with ascii zeroes till the end of the line and leave a certain amount of lines of ascii zeroes that can be filled later.
Now I'm making a test program to see if it works like I want it to, but it doesnt. The critical part of my code:
file = fopen("irasproba_tesztfajl.txt", "r+"); //it is previously loaded with 10 copies of the line I'll print later in reverse order
/* this finds the 3rd line */
int count = 0; //how much have we gone yet?
char c;
while(count != 2) {
if((c = fgetc(file)) == '\n') count++;
}
fflush(file);
fprintf(file, "- . , M N B V C X Y Í Ű Á É L K J H G F D S A Ú Ő P O I U Z T R E W Q Ó Ü Ö 9 8 7 6 5 4 3 2 1 0\n");
fflush(file);
fclose(file);
Now it does nothing, the file stays the same. What could be the problem?
Thank you.
From here,
When a file is opened with a "+"
option, you may both read and write on
it. However, you may not perform an
output operation immediately after an
input operation; you must perform an
intervening "rewind" or "fseek".
Similarly, you may not perform an
input operation immediately after an
output operation; you must perform an
intervening "rewind" or "fseek".
So you've achieved that with fflush, but in order to write to the desired location you need to fseek back. This is how I implemented it - could be better I guess:
/* this finds the 3rd line */
int count = 0; //how much have we gone yet?
char c;
int position_in_file;
while(count != 2) {
if((c = fgetc(file)) == '\n') count++;
}
// Store the position
position_in_file = ftell(file);
// Reposition it
fseek(file,position_in_file,SEEK_SET); // Or fseek(file,ftell(file),SEEK_SET);
fprintf(file, "- . , M N B V C X Y Í Ű Á É L K J H G F D S A Ú Ő P O I U Z T R E W Q Ó Ü Ö 9 8 7 6 5 4 3 2 1 0\n");
fclose(file);
Also, as has been commented, you should check if your file has been opened successfully, i.e. before reading/writing to file, check:
file = fopen("irasproba_tesztfajl.txt", "r+");
if(file == NULL)
{
printf("Unable to open file!");
exit(1);
}