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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#ifdef PIPE_GNUPLOT
#include <unistd.h>
#include <fcntl.h>
#endif // PIPE_GNUPLOT
#ifdef DYNAMIC_LOAD
#include <dlfcn.h>
void* handle = NULL;
#endif // DYNAMIC_LOAD
struct dval { double x, y; };
typedef double (*func_t)(double);
double sin2(double x) {
double y = sin(x);
return y*y;
}
double cos2(double x) {
double y = cos(x);
return y*y;
}
double __sincos(double x) {
// sin(x)cos(x) = sin(2x)/2
return sin(2*x)/2;
}
/// generates the table as asked in the task.
/// The core function of this file.
struct dval* get_table(func_t f, double start, double end, double step, long *length) {
long tlength = lround((end-start)/step);
struct dval* vals = calloc(tlength, sizeof(struct dval));
for (long i = 0; i < tlength; ++i) {
double x = start + step * i;
// Not accumulative because if step is too small,
// start will never increment
vals[i] = (struct dval){.x = x, .y = f(x)};
}
*length = tlength;
return vals;
}
void print_help(int status) {
const char *help =
"Usage: ./task2 -f func_name -o output_file [-h]\n"
"\t-h: this help\n"
"\t-f: function: either 'sin2', 'cos2' or 'sincos'.\n"
"\t\tif compiled with -DDYNAMIC_LOAD, file name with dynamic function.\n"
"\t-o: output file.\n\n"
"NOTE: the function in dynamic library must be named 'f'.\n"
"NOTE 2: with flag -DPIPE_GNUPLOT output will be piped in gnuplot\n.";
puts(help);
exit(status);
}
/// Get the function based on the command line flags - either use
/// existing or load one from dynamic library
func_t get_function(const char* name) {
if (!strcmp(name, "cos2"))
return &cos2;
if (!strcmp(name, "sin2"))
return &sin2;
if (!strcmp(name, "sincos"))
return &__sincos;
#ifndef DYNAMIC_LOAD
fputs("ERROR: unknown function. To use dynamic loading, compile with `-DDYNAMIC_LOAD`.\n", stderr);
exit(EXIT_FAILURE);
#else // DYNAMIC_LOAD
handle = dlopen(name, RTLD_NOW);
if (!handle) goto fail;
func_t f = dlsym(handle, "f");
if (!f) goto fail;
return f;
fail:
fputs(dlerror(), stderr);
exit(EXIT_FAILURE);
#endif // DYNAMIC_LOAD
}
void print_table(FILE* stream, const struct dval *table, long size) {
for (long i = 0; i < size; ++i) {
fprintf(stream, "%lg %lg\n", table[i].x, table[i].y);
}
}
int main(int argc, char *argv[]) {
func_t function = NULL;
const char *out = NULL;
// casual argument loop
for (int i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-h"))
print_help(EXIT_SUCCESS);
else if (!strcmp(argv[i], "-f"))
function = get_function(argv[++i]);
else if (!strcmp(argv[i], "-o"))
out = argv[++i];
else print_help(EXIT_FAILURE);
}
if (!function || !out) print_help(EXIT_SUCCESS);
long table_len;
struct dval *table = get_table(function, 0, 3, 0.01, &table_len);
// print data to stdout and to file
print_table(stdout, table, table_len);
FILE *f = fopen(out, "w+");
if (f) print_table(f, table, table_len);
else perror(out);
// This section is creating a 'gnuplot' pipe
// and writing data to it to be plotted
#ifdef PIPE_GNUPLOT
FILE* gp = popen("gnuplot", "w");
if (!gp) goto cleanup;
fputs("plot '-' with lines\n", gp);
print_table(gp, table, table_len);
fputs("e\n", gp);
fflush(gp);
getchar();
pclose(gp);
#endif // PIPE_GNUPLOT
cleanup:
fclose(f);
free(table);
#ifdef DYNAMIC_LOAD
if (handle) dlclose(handle);
#endif // DYNAMIC_LOAD
exit(EXIT_SUCCESS);
}
|