-
Notifications
You must be signed in to change notification settings - Fork 6
/
transpose.c
198 lines (160 loc) · 4.99 KB
/
transpose.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
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/* transpose: A stand-alone program
Usage: transpose file
Given a file that contains a rectangular matrix, replace the file with its transpose
Author: Bill Sacks
Creation date: 6/5/07
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "util.h"
#define SEPARATORS " \t\n\r" // valid separators between items on a line
void usage(char *progName) {
printf("Usage: %s filename\n", progName);
printf("Where filename is the file containing the data to transpose\n");
printf("This file must contain a rectangular matrix\n");
}
/* Count and return # of lines in f
Also return character count of the longest line in longestLine
- includes extra character to hold '\0'
Assume f is open for reading, and rewound
*/
int numlines(FILE *f, int *longestLine) {
int nl;
char c;
int length; // length of this line
int longLine;
nl = 0;
length = 0;
longLine = 0;
while ((c = fgetc(f)) != EOF) {
length++;
if (c == '\n') {
nl++;
if (length > longLine)
longLine = length;
length = 0;
}
}
*longestLine = longLine + 1; // add 1 to give space for '\0'
return nl;
}
/* Read file f into array of lines
PRE: f is open for reading and rewound
Each lines[i] is a character array of size maxLength,
and lines contains at least nl such character arrays, where nl is the number of lines in the file
POST: lines[i][j] will contain the jth character on the ith line
The file pointer f will be at the end of the file
*/
void readFile(FILE *f, char **lines, int maxLength) {
int i;
i=0;
while(fgets(lines[i], maxLength, f) != NULL) { // while not EOF or error
i++;
}
}
/* Count and return number of items in line
- items are separated by SEPARATORS
*/
int countItems(char *line) {
int n;
char *s;
char *lineCopy;
lineCopy = (char *)malloc((strlen(line) + 1) * sizeof(char));
strcpy(lineCopy, line);
n = 0;
s = strtok(lineCopy, SEPARATORS);
while (s != NULL) {
n++;
s = strtok(NULL, SEPARATORS);
}
free(lineCopy);
return n;
}
/* Read individual items from lines into items
items[i][j] will hold a pointer to the jth item (j = 0..numItems-1) in the ith line (i = 0..numLines-1)
- items are separated by SEPARATORS
There must be exactly numItems items on each line
*/
void readItems(char **lines, char ***items, int numLines, int numItems) {
int i, j;
for (i = 0; i < numLines; i++) {
items[i][0] = strtok(lines[i], SEPARATORS);
for (j = 1; j < numItems; j++)
items[i][j] = strtok(NULL, SEPARATORS);
if (items[i][numItems - 1] == NULL) {
printf("ERROR: Too few items on line %d\n", i+1);
exit(1);
}
if (strtok(NULL, SEPARATORS) != NULL) { // more items on the line!
printf("ERROR: Too many items on line %d\n", i+1);
exit(1);
}
}
}
/* Write out the transposed items to f
f must be open for writing
items[i][j] holds the jth item (j = 0..numItems-1) on the ith line (i = 0..numLines-1)
We output all items #0 on the first line, all items #1 on the second line, etc.
Items are separated by spaces in the output file
*/
void outputTranspose(FILE *f, char ***items, int numLines, int numItems) {
int i, j;
for (j = 0; j < numItems; j++) {
for (i = 0; i < numLines; i++) {
fprintf(f, "%s ", items[i][j]);
}
fprintf(f, "\n");
}
}
int main(int argc, char *argv[]) {
FILE *f;
char *filename; // name of file to transpose
char *tmpName; // name of a temporary file
int nl; // number of lines
int longestLine; // length of longest line
int numItems; // number of items in each line
char **lines; // array of character arrays, holding all lines in file
char ***items; /* 2-d array of character pointers, holding pointers to various points in the lines array
items[i][j] holds a pointer to the jth item in the ith line */
int i;
if (argc != 2) {
usage(argv[0]);
exit(1);
}
filename = argv[1];
f = openFile(filename, "r");
nl = numlines(f, &longestLine);
rewind(f);
// Allocate space to hold the file, line by line:
lines = (char **)malloc(nl * sizeof(char *));
for (i = 0; i < nl; i++) {
lines[i] = (char *)malloc(longestLine * sizeof(char));
}
readFile(f, lines, longestLine);
fclose(f);
// Allocate space to hold the individual items:
numItems = countItems(lines[0]);
items = (char ***)malloc(nl * sizeof(char **));
for (i = 0; i < nl; i++) {
items[i] = (char **)malloc(numItems * sizeof(char *));
}
readItems(lines, items, nl, numItems);
// Output to file, replacing existing file:
tmpName = (char *)malloc((strlen(filename) + 5) * sizeof(char));
strcpy(tmpName, filename);
strcat(tmpName, ".bak");
rename(filename, tmpName); // keep a backup in case things crash
f = openFile(filename, "w");
outputTranspose(f, items, nl, numItems);
fclose(f);
remove(tmpName);
// Free space:
for (i = 0; i < nl; i++) {
free(items[i]);
free(lines[i]);
}
free(items);
free(lines);
return 0;
}