Skip to content

Commit 3dc2e12

Browse files
committed
final commit
1 parent eeb4c3c commit 3dc2e12

File tree

14 files changed

+2013
-79
lines changed

14 files changed

+2013
-79
lines changed

‎2025/fin/README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# 41247044S
22

3-
p1:
3+
p1: make sure to have libcurl and pdftotext, I have given you the popper tar, please do it yourself!
44

5-
p2:
5+
p2: please have libcurl and json-c library!
66

7-
p3:
7+
p3: no deps i think...

‎2025/fin/fin01.c‎

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
/*
2+
* fin01.c
3+
*
4+
* Pipeline:
5+
* 1) Download PDF using libcurl
6+
* 2) Convert PDF to text using pdftotext (requires Poppler utils)
7+
* 3) Parse the text output to extract a table of state data
8+
* 4) Offer menu to sort and display
9+
*
10+
* Build:
11+
* gcc -o fin01 fin01.c -lcurl
12+
*
13+
* Requirements:
14+
* - libcurl-dev
15+
* - poppler-utils (for pdftotext)
16+
*/
17+
18+
#include <stdio.h>
19+
#include <stdlib.h>
20+
#include <string.h>
21+
#include <curl/curl.h>
22+
23+
typedef struct {
24+
char state[64];
25+
int start_salary;
26+
int avg_salary;
27+
int min_wage;
28+
int per_student_spending;
29+
int he_earn;
30+
int he_fac_salary;
31+
} StateData;
32+
33+
#define MAX_STATES 60
34+
static StateData states[MAX_STATES];
35+
static int num_states = 0;
36+
37+
// libcurl write callback
38+
static size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
39+
return fwrite(ptr, size, nmemb, stream);
40+
}
41+
42+
// Download the PDF
43+
void download_pdf(const char *url, const char *outfile) {
44+
CURL *curl = curl_easy_init();
45+
if (!curl) {
46+
fprintf(stderr, "Failed to init curl\n");
47+
exit(1);
48+
}
49+
FILE *fp = fopen(outfile, "wb");
50+
curl_easy_setopt(curl, CURLOPT_URL, url);
51+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
52+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
53+
CURLcode res = curl_easy_perform(curl);
54+
curl_easy_cleanup(curl);
55+
fclose(fp);
56+
if (res != CURLE_OK) {
57+
fprintf(stderr, "Error downloading PDF: %s\n", curl_easy_strerror(res));
58+
exit(1);
59+
}
60+
printf("PDF downloaded to %s\n", outfile);
61+
}
62+
63+
// Convert PDF to text
64+
void pdf_to_text(const char *pdf, const char *txt) {
65+
char cmd[512];
66+
snprintf(cmd, sizeof(cmd), "pdftotext -layout %s %s", pdf, txt);
67+
printf("Running: %s\n", cmd);
68+
int rc = system(cmd);
69+
if (rc != 0) {
70+
fprintf(stderr, "pdftotext conversion failed\n");
71+
exit(1);
72+
}
73+
}
74+
75+
// Parse the text file output
76+
void parse_text(const char *txtfile) {
77+
FILE *fp = fopen(txtfile, "r");
78+
if (!fp) { perror("fopen"); exit(1); }
79+
char line[256];
80+
int in_table = 0;
81+
num_states = 0;
82+
while (fgets(line, sizeof(line), fp)) {
83+
// Trim newline
84+
line[strcspn(line, "\r\n")] = 0;
85+
if (!in_table) {
86+
// detect table header line containing "State" and "Starting"
87+
if (strstr(line, "State") && strstr(line, "Starting")) {
88+
in_table = 1;
89+
// skip header underline
90+
fgets(line, sizeof(line), fp);
91+
}
92+
} else {
93+
if (strlen(line) < 10) break; // end of table
94+
// Expect fixed-width columns, parse by substrings
95+
char state_name[64];
96+
char buf[16];
97+
// columns: State [0-20], StartSalary [20-30], AvgSalary [30-40], MinWage [40-50], PerStudent [50-60], HEearn [60-70], HEfac [70-80]
98+
strncpy(state_name, line, 20); state_name[20] = 0;
99+
// cleanup
100+
char *s = state_name;
101+
while (*s == ' ') s++;
102+
strcpy(states[num_states].state, s);
103+
// parse ints
104+
strncpy(buf, line+20, 10); buf[10]=0; states[num_states].start_salary = atoi(buf);
105+
strncpy(buf, line+30, 10); buf[10]=0; states[num_states].avg_salary = atoi(buf);
106+
strncpy(buf, line+40, 10); buf[10]=0; states[num_states].min_wage = atoi(buf);
107+
strncpy(buf, line+50, 10); buf[10]=0; states[num_states].per_student_spending = atoi(buf);
108+
strncpy(buf, line+60, 10); buf[10]=0; states[num_states].he_earn = atoi(buf);
109+
strncpy(buf, line+70, 10); buf[10]=0; states[num_states].he_fac_salary = atoi(buf);
110+
num_states++;
111+
}
112+
}
113+
fclose(fp);
114+
printf("Parsed %d states\n", num_states);
115+
}
116+
117+
// Comparator functions for all 14 menu options
118+
int cmp_start_asc(const void *a, const void *b) {
119+
return ((StateData*)a)->start_salary - ((StateData*)b)->start_salary;
120+
}
121+
int cmp_start_desc(const void *a, const void *b) {
122+
return ((StateData*)b)->start_salary - ((StateData*)a)->start_salary;
123+
}
124+
int cmp_avg_asc(const void *a, const void *b) {
125+
return ((StateData*)a)->avg_salary - ((StateData*)b)->avg_salary;
126+
}
127+
int cmp_avg_desc(const void *a, const void *b) {
128+
return ((StateData*)b)->avg_salary - ((StateData*)a)->avg_salary;
129+
}
130+
int cmp_start_min_gap_asc(const void *a, const void *b) {
131+
int gap_a = ((StateData*)a)->start_salary - ((StateData*)a)->min_wage;
132+
int gap_b = ((StateData*)b)->start_salary - ((StateData*)b)->min_wage;
133+
return gap_a - gap_b;
134+
}
135+
int cmp_start_min_gap_desc(const void *a, const void *b) {
136+
int gap_a = ((StateData*)a)->start_salary - ((StateData*)a)->min_wage;
137+
int gap_b = ((StateData*)b)->start_salary - ((StateData*)b)->min_wage;
138+
return gap_b - gap_a;
139+
}
140+
int cmp_avg_min_gap_asc(const void *a, const void *b) {
141+
int gap_a = ((StateData*)a)->avg_salary - ((StateData*)a)->min_wage;
142+
int gap_b = ((StateData*)b)->avg_salary - ((StateData*)b)->min_wage;
143+
return gap_a - gap_b;
144+
}
145+
int cmp_avg_min_gap_desc(const void *a, const void *b) {
146+
int gap_a = ((StateData*)a)->avg_salary - ((StateData*)a)->min_wage;
147+
int gap_b = ((StateData*)b)->avg_salary - ((StateData*)b)->min_wage;
148+
return gap_b - gap_a;
149+
}
150+
int cmp_per_student_asc(const void *a, const void *b) {
151+
return ((StateData*)a)->per_student_spending - ((StateData*)b)->per_student_spending;
152+
}
153+
int cmp_per_student_desc(const void *a, const void *b) {
154+
return ((StateData*)b)->per_student_spending - ((StateData*)a)->per_student_spending;
155+
}
156+
int cmp_start_he_gap_asc(const void *a, const void *b) {
157+
int gap_a = ((StateData*)a)->start_salary - ((StateData*)a)->he_earn;
158+
int gap_b = ((StateData*)b)->start_salary - ((StateData*)b)->he_earn;
159+
return gap_a - gap_b;
160+
}
161+
int cmp_start_he_gap_desc(const void *a, const void *b) {
162+
int gap_a = ((StateData*)a)->start_salary - ((StateData*)a)->he_earn;
163+
int gap_b = ((StateData*)b)->start_salary - ((StateData*)b)->he_earn;
164+
return gap_b - gap_a;
165+
}
166+
int cmp_avg_hefac_gap_asc(const void *a, const void *b) {
167+
int gap_a = ((StateData*)a)->avg_salary - ((StateData*)a)->he_fac_salary;
168+
int gap_b = ((StateData*)b)->avg_salary - ((StateData*)b)->he_fac_salary;
169+
return gap_a - gap_b;
170+
}
171+
int cmp_avg_hefac_gap_desc(const void *a, const void *b) {
172+
int gap_a = ((StateData*)a)->avg_salary - ((StateData*)a)->he_fac_salary;
173+
int gap_b = ((StateData*)b)->avg_salary - ((StateData*)b)->he_fac_salary;
174+
return gap_b - gap_a;
175+
}
176+
177+
// Display top results with appropriate data based on sort type
178+
void display_states(int limit, int sort_type) {
179+
for (int i = 0; i < limit && i < num_states; i++) {
180+
printf("%2d. %-20s", i+1, states[i].state);
181+
182+
switch (sort_type) {
183+
case 1: case 2: // Starting salary sorts
184+
printf(" %6d\n", states[i].start_salary);
185+
break;
186+
case 3: case 4: // Average salary sorts
187+
printf(" %6d\n", states[i].avg_salary);
188+
break;
189+
case 5: case 6: // Starting salary vs minimum wage gap
190+
printf(" %6d\n", states[i].start_salary - states[i].min_wage);
191+
break;
192+
case 7: case 8: // Average salary vs minimum wage gap
193+
printf(" %6d\n", states[i].avg_salary - states[i].min_wage);
194+
break;
195+
case 9: case 10: // Per student spending
196+
printf(" %6d\n", states[i].per_student_spending);
197+
break;
198+
case 11: case 12: // Starting salary vs HE ESP earnings gap
199+
printf(" %6d\n", states[i].start_salary - states[i].he_earn);
200+
break;
201+
case 13: case 14: // Average salary vs HE faculty salary gap
202+
printf(" %6d\n", states[i].avg_salary - states[i].he_fac_salary);
203+
break;
204+
default:
205+
printf(" %6d %6d %6d\n", states[i].start_salary, states[i].avg_salary, states[i].min_wage);
206+
}
207+
}
208+
}
209+
210+
int main() {
211+
const char *pdf_url = "https://www.nea.org/sites/default/files/2025-04/2025_rankings_and_estimates_report.pdf";
212+
download_pdf(pdf_url, "report.pdf");
213+
pdf_to_text("report.pdf", "report.txt");
214+
parse_text("report.txt");
215+
216+
int choice;
217+
do {
218+
printf("---\n");
219+
printf("1) Sort states in the ascending order based on \"Average Teacher Starting Salary\"\n");
220+
printf("2) Sort states in the descending order based on \"Average Teacher Starting Salary\"\n");
221+
printf("3) Sort states in the ascending order based on \"Average Teacher Salary\"\n");
222+
printf("4) Sort states in the descending order based on \"Average Teacher Salary\"\n");
223+
printf("5) Sort states in the ascending order based on gap between \"Average Starting Teacher Salary\" and \"Minimum Living Wage\"\n");
224+
printf("6) Sort states in the descending order based on gap between \"Average Starting Teacher Salary\" and \"Minimum Living Wage\"\n");
225+
printf("7) Sort states in the ascending order based on gap between \"Average Teacher Salary\" and \"Minimum Living Wage\"\n");
226+
printf("8) Sort states in the descending order based on gap between \"Average Teacher Salary\" and \"Minimum Living Wage\"\n");
227+
printf("9) Sort states in the ascending order based on \"Per Student Spending\"\n");
228+
printf("10) Sort states in the descending order based on \"Per Student Spending\"\n");
229+
printf("11) Sort states in the ascending order based on gap between \"Average Starting Teacher Salary\" and \"Average HE ESP Earnings\"\n");
230+
printf("12) Sort states in the descending order based on gap between \"Average Starting Teacher Salary\" and \"Average HE ESP Earnings\"\n");
231+
printf("13) Sort states in the ascending order based on gap between \"Average Teacher Salary\" and \"Average Higher Ed Faculty Salary\"\n");
232+
printf("14) Sort states in the descending order based on gap between \"Average Teacher Salary\" and \"Average Higher Ed Faculty Salary\"\n");
233+
printf("15) Exit\n");
234+
printf("---\n");
235+
printf("Please enter your choice: ");
236+
scanf("%d", &choice);
237+
switch (choice) {
238+
case 1:
239+
qsort(states, num_states, sizeof(StateData), cmp_start_asc);
240+
display_states(10, choice);
241+
break;
242+
case 2:
243+
qsort(states, num_states, sizeof(StateData), cmp_start_desc);
244+
display_states(10, choice);
245+
break;
246+
case 3:
247+
qsort(states, num_states, sizeof(StateData), cmp_avg_asc);
248+
display_states(10, choice);
249+
break;
250+
case 4:
251+
qsort(states, num_states, sizeof(StateData), cmp_avg_desc);
252+
display_states(10, choice);
253+
break;
254+
case 5:
255+
qsort(states, num_states, sizeof(StateData), cmp_start_min_gap_asc);
256+
display_states(10, choice);
257+
break;
258+
case 6:
259+
qsort(states, num_states, sizeof(StateData), cmp_start_min_gap_desc);
260+
display_states(10, choice);
261+
break;
262+
case 7:
263+
qsort(states, num_states, sizeof(StateData), cmp_avg_min_gap_asc);
264+
display_states(10, choice);
265+
break;
266+
case 8:
267+
qsort(states, num_states, sizeof(StateData), cmp_avg_min_gap_desc);
268+
display_states(10, choice);
269+
break;
270+
case 9:
271+
qsort(states, num_states, sizeof(StateData), cmp_per_student_asc);
272+
display_states(10, choice);
273+
break;
274+
case 10:
275+
qsort(states, num_states, sizeof(StateData), cmp_per_student_desc);
276+
display_states(10, choice);
277+
break;
278+
case 11:
279+
qsort(states, num_states, sizeof(StateData), cmp_start_he_gap_asc);
280+
display_states(10, choice);
281+
break;
282+
case 12:
283+
qsort(states, num_states, sizeof(StateData), cmp_start_he_gap_desc);
284+
display_states(10, choice);
285+
break;
286+
case 13:
287+
qsort(states, num_states, sizeof(StateData), cmp_avg_hefac_gap_asc);
288+
display_states(10, choice);
289+
break;
290+
case 14:
291+
qsort(states, num_states, sizeof(StateData), cmp_avg_hefac_gap_desc);
292+
display_states(10, choice);
293+
break;
294+
case 15:
295+
printf("Goodbye!\n");
296+
break;
297+
default:
298+
printf("Not implemented yet.\n");
299+
}
300+
} while (choice != 15);
301+
302+
return 0;
303+
}

0 commit comments

Comments
 (0)