README
Using and Understanding the Greetings C Program
This project is based on the source code from the book “Tiny C Projects”. The code for this project can be found on my GitHub at Greetings.
Site: https://github.com/artwalker/TinyProject/tree/main/cprog/greetings
There are also implementations of this project in other programming languages.
Project Analysis
This project is a C language program, the main function of which is to randomly select and print a quote from a text file. The print_random_saying
function in the project is responsible for this function. This function is declared in the pithy.h
header file and defined in the pithy.c
source file.
The project uses a Makefile to automate the compilation and linking process. The Makefile defines several rules for compiling source files (greet.c
and pithy.c
), linking the generated object files (greet.o
and pithy.o
), and creating an executable file (greetings
). The Makefile also defines a rule for creating symbolic links to the pithy.txt
file and the greetings
executable file.
Usage Guide
Compile the project: In the terminal, navigate to the directory containing the Makefile, then enter
make
ormake all
. This will compile the source files, link the generated object files to create an executable file.Run the program: In the terminal, navigate to the
~/bin
directory, then enter./greetings
. This will run the program, and the program will randomly select and print a quote from thepithy.txt
file.Clean up the project: If you want to delete the generated executable file and object files, as well as the links created in the
~/bin
directory, you can entermake clean
in the terminal.Configure .zshrc: If you want to automatically run the
greetings
program when starting a new shell session, you can add the following line to the.zshrc
file:
1
cd ~/bin && ./greeting Ethan && cd
This will first switch to the ~/bin
directory, then run the greetings
program.
Note: This project assumes that you have installed a C compiler (such as clang) on your system. If you do not have a C compiler installed on your system, you need to install a C compiler to compile and run this project.
Code Anylysis
tree
1
2
3
4
5
6
7
8
./cprog
└── greetings
├── Makefile
├── README.md
├── greet.c
├── pithy.c
├── pithy.h
└── pithy.txt
greet.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define BSIZE 256
/**
* Function to print a random saying from a file.
* @param filename The name of the file containing the sayings.
*/
void print_random_saying(const char *filename)
{
FILE *fp; // File pointer
char buffer[BSIZE]; // Buffer to store lines from the file
char *r, *entry; // Pointers to store the result of fgets and the allocated memory for each line
int items, saying; // Number of items read from the file and the index of the selected saying
char **list_base; // Base of the list of sayings
// Open the file
fp = fopen(filename, "r");
if (fp == NULL)
{
fprintf(stderr, "Unable to open file %s\n", filename);
exit(1);
}
// Allocate initial memory for the list of sayings
list_base = malloc(sizeof(char *) * 100);
if (list_base == NULL)
{
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
items = 0;
// Read lines from the file until EOF
while (!feof(fp))
{
r = fgets(buffer, BSIZE, fp);
if (r == NULL)
break;
// Allocate memory for the current line and copy it from the buffer
entry = malloc(sizeof(char) * strlen(buffer) + 1);
if (entry == NULL)
{
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
strcpy(entry, buffer);
// Store the pointer to the current line in the list
*(list_base + items) = entry;
items++;
// If the list is full, reallocate more memory
if (items % 100 == 0)
{
list_base = realloc(list_base, sizeof(char *) * (items + 100));
if (list_base == NULL)
{
fprintf(stderr, "Unable to reallocate memory\n");
exit(1);
}
}
}
// Close the file
fclose(fp);
// Seed the random number generator and select a random saying
srand((unsigned)time(NULL));
saying = rand() % (items - 1);
// Print the selected saying
printf("%s", *(list_base + saying));
// Free the allocated memory
for (int x = 0; x < items; x++)
free(*(list_base + x));
free(list_base);
}
// int main()
// {
// print_random_saying("pithy.txt");
// return (0);
// }
pithy.h
1
2
3
4
5
6
7
8
9
10
#ifndef PITHY_H
#define PITHY_H
/**
* Function to print a random saying from a file.
* @param filename The name of the file containing the sayings.
*/
void print_random_saying(const char *filename);
#endif // PITHY_H
pithy.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <stdio.h>
#include <time.h>
// Include the header file for pithy06
#include "pithy.h"
/**
* Function to calculate the phase of the moon for a given date.
* @param year The year of the date.
* @param month The month of the date.
* @param day The day of the date.
* @return The phase of the moon as an integer between 0 and 7.
*/
int moon_phase(int year, int month, int day);
/**
* Main function of the program.
* @param argc The number of command line arguments.
* @param argv The command line arguments.
* @return 0 if the program finishes successfully.
*/
int main(int argc, char *argv[])
{
time_t now; // Current time
struct tm *clock; // Local time
char time_string[64]; // Formatted time string
// Phases of the moon
char *phase[8] = {
"waxing crescent", "at first quarter",
"waxing gibbous", "full", "waning gibbous",
"at last quarter", "waning crescent", "new"};
int mp; // Moon phase
time(&now); // Get current time
clock = localtime(&now); // Convert to local time
// Format time as a string
strftime(time_string, 64, "Today is %A, %B %d, %Y%nIt is %r%n", clock);
// Calculate moon phase
mp = moon_phase(clock->tm_year + 1900, clock->tm_mon, clock->tm_mday);
printf("Greetings"); // Print greeting
if (argc > 1) // If there is more than one command line argument
printf(", %s", argv[1]); // Print the second command line argument
printf("!\n%s", time_string); // Print the time string
printf("The moon is %s\n", phase[mp]); // Print the moon phase
// Call the function from pithy06
print_random_saying("pithy.txt");
return (0); // End the program
}
/**
* Function to calculate the phase of the moon for a given date.
* @param year The year of the date.
* @param month The month of the date.
* @param day The day of the date.
* @return The phase of the moon as an integer between 0 and 7.
*/
int moon_phase(int year, int month, int day)
{
int d, g, e; // Day, golden number, and epact
d = day; // Store the day
if (month == 2) // If the month is February
d += 31; // Add 31 to the day
else if (month > 2) // If the month is after February
d += 59 + (month - 3) * 30.6 + 0.5; // Add the number of days in the previous months to the day
g = (year - 1900) % 19; // Calculate the golden number
e = (11 * g + 29) % 30; // Calculate the epact
if (e == 25 || e == 24) // If the epact is 25 or 24
++e; // Increment the epact
return ((((e + d) * 6 + 5) % 177) / 22 & 7); // Calculate and return the phase of the moon
}
Makefile
# Set the compiler to clang
CC = clang
# Set the compiler flags to enable all warnings and debugging information
CFLAGS = -Wall -g
# Set the target executable name
TARGET = greetings
# Set the name of the file containing the sayings
FILE = pithy
# Set the destination directory for the symbolic links
DESTDIR = ~/bin
# Default target
all: $(TARGET) link
# Link the object files to create the target executable
$(TARGET): greet.o pithy.o
$(CC) $(CFLAGS) -o $(TARGET) greet.o pithy.o
# Compile the greet.c source file into the greet.o object file
greet.o: greet.c pithy.h
$(CC) $(CFLAGS) -c greet.c
# Compile the pithy.c source file into the pithy.o object file
pithy.o: pithy.c pithy.h
$(CC) $(CFLAGS) -c pithy.c
# Create symbolic links to the target executable and the sayings file in the destination directory
link:
ln -s $(PWD)/$(TARGET) $(DESTDIR)
ln -s $(PWD)/$(FILE).txt $(DESTDIR)
# Remove the target executable, the object files, and the symbolic links
clean:
rm -f $(TARGET) *.o
rm -f $(DESTDIR)/$(TARGET)
rm -f $(DESTDIR)/$(FILE).txt
pithy.txt
Politics exists so that uncoordinated people can play sports.
Water alone doesn't get you clean. You must use soap. That's because dirt and crud loves soap and sticks to it really well. The water then washes away the soap, along with the dirt, and the result is that you are clean.
You buy popcorn, soda, and candy so that you have something to eat before the movie starts.
Just wait until Starbucks figures out that you can snort coffee.
Nothing instills more doubt in the curious than the sign "Wet Paint."
You might dislike texting, but it certainly does get annoying people to shut up.
You know you have an eating problem when you finish a meal and think, "Boy! When can I do that again?"
The middle of nowhere is equidistant from everywhere else.
Marketing wizards are looking for the human equivalent of what a dog feels at the sound of a can opener.
Having a pet ensures that you don't freak out over every noise in the house. Loud bang? It's the cat. So what if the cat is in the room with me. It's the cat.
The true experience at an amusement park is waiting in lines.
There is no logic in the computer industry.
The car's manual calls it the "check engine" lamp, but I call it the "This is going to cost at least $200" light.
You drive on a parkway and park on a driveway.
Do I take a break from work to play a video game, or take a break from a video game to get work done?