rjhead 0.2.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/ext/changes.txt +351 -0
- data/ext/exif.c +1629 -0
- data/ext/extconf.rb +0 -0
- data/ext/gpsinfo.c +217 -0
- data/ext/iptc.c +205 -0
- data/ext/jhead.1 +409 -0
- data/ext/jhead.c +1697 -0
- data/ext/jhead.h +251 -0
- data/ext/jhead.spec +149 -0
- data/ext/jpgfile.c +738 -0
- data/ext/make.bat +1 -0
- data/ext/makefile +23 -0
- data/ext/makefile-win32 +27 -0
- data/ext/makernote.c +184 -0
- data/ext/myglob.c +305 -0
- data/ext/paths.c +140 -0
- data/ext/readme.txt +60 -0
- data/ext/usage.html +469 -0
- data/lib/rjhead.rb +0 -0
- data/rjhead.gemspec +73 -0
- data/setup.rake +1 -0
- data/test/rjhead_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +94 -0
data/ext/make.bat
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
nmake -f makefile-win32
|
data/ext/makefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#--------------------------------
|
2
|
+
# jhead makefile for Unix
|
3
|
+
#--------------------------------
|
4
|
+
OBJ=.
|
5
|
+
SRC=.
|
6
|
+
CFLAGS= -O3 -Wall
|
7
|
+
|
8
|
+
all: jhead
|
9
|
+
|
10
|
+
objs = $(OBJ)/jhead.o $(OBJ)/jpgfile.o $(OBJ)/paths.o \
|
11
|
+
$(OBJ)/exif.o $(OBJ)/iptc.o $(OBJ)/gpsinfo.o $(OBJ)/makernote.o
|
12
|
+
|
13
|
+
$(OBJ)/%.o:$(SRC)/%.c
|
14
|
+
${CC} $(CFLAGS) -c $< -o $@
|
15
|
+
|
16
|
+
jhead: $(objs) jhead.h
|
17
|
+
${CC} -o jhead $(objs) -lm
|
18
|
+
|
19
|
+
clean:
|
20
|
+
rm -f $(objs) jhead
|
21
|
+
|
22
|
+
install:
|
23
|
+
mkdir -p ../bin; cp jhead ../bin/jhead
|
data/ext/makefile-win32
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#--------------------------------
|
2
|
+
# jhead makefile for Win32
|
3
|
+
#--------------------------------
|
4
|
+
|
5
|
+
CC=cl /nologo
|
6
|
+
CFLAGS=-c -G3 -Ox -W3 -Zp -Zd
|
7
|
+
LINKER=link
|
8
|
+
LINKCON = /nologo
|
9
|
+
|
10
|
+
all:jhead.exe
|
11
|
+
|
12
|
+
OBJ = .
|
13
|
+
|
14
|
+
OBJECTS_JHEAD = $(OBJ)\jhead.obj \
|
15
|
+
$(OBJ)\jpgfile.obj \
|
16
|
+
$(OBJ)\myglob.obj \
|
17
|
+
$(OBJ)\paths.obj \
|
18
|
+
$(OBJ)\exif.obj \
|
19
|
+
$(OBJ)\iptc.obj \
|
20
|
+
$(OBJ)\gpsinfo.obj \
|
21
|
+
$(OBJ)\makernote.obj
|
22
|
+
|
23
|
+
$(OBJECTS_JHEAD): $(@B).c jhead.h
|
24
|
+
$(CC) /Fo$(OBJ)\ $(CFLAGS) $(@B).c
|
25
|
+
|
26
|
+
jhead.exe: $(OBJECTS_JHEAD)
|
27
|
+
$(LINKER) $(LINKCON) -OUT:jhead.exe $(OBJECTS_JHEAD)
|
data/ext/makernote.c
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
//--------------------------------------------------------------------------
|
2
|
+
// Parse some maker specific onformation.
|
3
|
+
// (Very limited right now - add maker specific stuff to this module)
|
4
|
+
//--------------------------------------------------------------------------
|
5
|
+
#include "jhead.h"
|
6
|
+
|
7
|
+
//--------------------------------------------------------------------------
|
8
|
+
// Process exif format directory, as used by Cannon maker note
|
9
|
+
//--------------------------------------------------------------------------
|
10
|
+
void ProcessCanonMakerNoteDir(unsigned char * DirStart, unsigned char * OffsetBase,
|
11
|
+
unsigned ExifLength)
|
12
|
+
{
|
13
|
+
int de;
|
14
|
+
int a;
|
15
|
+
int NumDirEntries;
|
16
|
+
|
17
|
+
NumDirEntries = Get16u(DirStart);
|
18
|
+
#define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
|
19
|
+
|
20
|
+
{
|
21
|
+
unsigned char * DirEnd;
|
22
|
+
DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
|
23
|
+
if (DirEnd > (OffsetBase+ExifLength)){
|
24
|
+
ErrNonfatal("Illegally sized Exif makernote subdir (%d entries)",NumDirEntries,0);
|
25
|
+
return;
|
26
|
+
}
|
27
|
+
|
28
|
+
if (DumpExifMap){
|
29
|
+
printf("Map: %05d-%05d: Directory (makernote)\n",(int)(DirStart-OffsetBase), (int)(DirEnd-OffsetBase));
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
if (ShowTags){
|
34
|
+
printf("(dir has %d entries)\n",NumDirEntries);
|
35
|
+
}
|
36
|
+
|
37
|
+
for (de=0;de<NumDirEntries;de++){
|
38
|
+
int Tag, Format, Components;
|
39
|
+
unsigned char * ValuePtr;
|
40
|
+
int ByteCount;
|
41
|
+
unsigned char * DirEntry;
|
42
|
+
DirEntry = DIR_ENTRY_ADDR(DirStart, de);
|
43
|
+
|
44
|
+
Tag = Get16u(DirEntry);
|
45
|
+
Format = Get16u(DirEntry+2);
|
46
|
+
Components = Get32u(DirEntry+4);
|
47
|
+
|
48
|
+
if ((Format-1) >= NUM_FORMATS) {
|
49
|
+
// (-1) catches illegal zero case as unsigned underflows to positive large.
|
50
|
+
ErrNonfatal("Illegal Exif number format %d for maker tag %04x", Format, Tag);
|
51
|
+
continue;
|
52
|
+
}
|
53
|
+
|
54
|
+
if ((unsigned)Components > 0x10000){
|
55
|
+
ErrNonfatal("Too many components (%d) for Exif maker tag %04x", Components, Tag);
|
56
|
+
continue;
|
57
|
+
}
|
58
|
+
|
59
|
+
ByteCount = Components * BytesPerFormat[Format];
|
60
|
+
|
61
|
+
if (ByteCount > 4){
|
62
|
+
unsigned OffsetVal;
|
63
|
+
OffsetVal = Get32u(DirEntry+8);
|
64
|
+
// If its bigger than 4 bytes, the dir entry contains an offset.
|
65
|
+
if (OffsetVal+ByteCount > ExifLength){
|
66
|
+
// Bogus pointer offset and / or bytecount value
|
67
|
+
ErrNonfatal("Illegal value pointer for Exif maker tag %04x", Tag,0);
|
68
|
+
continue;
|
69
|
+
}
|
70
|
+
ValuePtr = OffsetBase+OffsetVal;
|
71
|
+
|
72
|
+
if (DumpExifMap){
|
73
|
+
printf("Map: %05d-%05d: Data for makernote tag %04x\n",OffsetVal, OffsetVal+ByteCount, Tag);
|
74
|
+
}
|
75
|
+
}else{
|
76
|
+
// 4 bytes or less and value is in the dir entry itself
|
77
|
+
ValuePtr = DirEntry+8;
|
78
|
+
}
|
79
|
+
|
80
|
+
if (ShowTags){
|
81
|
+
// Show tag name
|
82
|
+
printf(" Canon maker tag %04x Value = ", Tag);
|
83
|
+
}
|
84
|
+
|
85
|
+
// Show tag value.
|
86
|
+
switch(Format){
|
87
|
+
|
88
|
+
case FMT_UNDEFINED:
|
89
|
+
// Undefined is typically an ascii string.
|
90
|
+
|
91
|
+
case FMT_STRING:
|
92
|
+
// String arrays printed without function call (different from int arrays)
|
93
|
+
if (ShowTags){
|
94
|
+
printf("\"");
|
95
|
+
for (a=0;a<ByteCount;a++){
|
96
|
+
int ZeroSkipped = 0;
|
97
|
+
if (ValuePtr[a] >= 32){
|
98
|
+
if (ZeroSkipped){
|
99
|
+
printf("?");
|
100
|
+
ZeroSkipped = 0;
|
101
|
+
}
|
102
|
+
putchar(ValuePtr[a]);
|
103
|
+
}else{
|
104
|
+
if (ValuePtr[a] == 0){
|
105
|
+
ZeroSkipped = 1;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}
|
109
|
+
printf("\"\n");
|
110
|
+
}
|
111
|
+
break;
|
112
|
+
|
113
|
+
default:
|
114
|
+
if (ShowTags){
|
115
|
+
PrintFormatNumber(ValuePtr, Format, ByteCount);
|
116
|
+
printf("\n");
|
117
|
+
}
|
118
|
+
}
|
119
|
+
if (Tag == 1 && Components > 16){
|
120
|
+
int IsoCode = Get16u(ValuePtr + 16*sizeof(unsigned short));
|
121
|
+
if (IsoCode >= 16 && IsoCode <= 24){
|
122
|
+
ImageInfo.ISOequivalent = 50 << (IsoCode-16);
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
if (Tag == 4 && Format == FMT_USHORT){
|
127
|
+
if (Components > 7){
|
128
|
+
int WhiteBalance = Get16u(ValuePtr + 7*sizeof(unsigned short));
|
129
|
+
switch(WhiteBalance){
|
130
|
+
// 0=Auto, 6=Custom
|
131
|
+
case 1: ImageInfo.LightSource = 1; break; // Sunny
|
132
|
+
case 2: ImageInfo.LightSource = 1; break; // Cloudy
|
133
|
+
case 3: ImageInfo.LightSource = 3; break; // Thungsten
|
134
|
+
case 4: ImageInfo.LightSource = 2; break; // Fourescent
|
135
|
+
case 5: ImageInfo.LightSource = 4; break; // Flash
|
136
|
+
}
|
137
|
+
}
|
138
|
+
if (Components > 19 && ImageInfo.Distance <= 0) {
|
139
|
+
// Indicates the distance the autofocus camera is focused to.
|
140
|
+
// Tends to be less accurate as distance increases.
|
141
|
+
int temp_dist = Get16u(ValuePtr + 19*sizeof(unsigned short));
|
142
|
+
if (temp_dist != 65535){
|
143
|
+
ImageInfo.Distance = (float)temp_dist/100;
|
144
|
+
}else{
|
145
|
+
ImageInfo.Distance = -1 /* infinity */;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
|
152
|
+
//--------------------------------------------------------------------------
|
153
|
+
// Show generic maker note - just hex bytes.
|
154
|
+
//--------------------------------------------------------------------------
|
155
|
+
void ShowMakerNoteGeneric(unsigned char * ValuePtr, int ByteCount)
|
156
|
+
{
|
157
|
+
int a;
|
158
|
+
for (a=0;a<ByteCount;a++){
|
159
|
+
if (a > 10){
|
160
|
+
printf("...");
|
161
|
+
break;
|
162
|
+
}
|
163
|
+
printf(" %02x",ValuePtr[a]);
|
164
|
+
}
|
165
|
+
printf(" (%d bytes)", ByteCount);
|
166
|
+
printf("\n");
|
167
|
+
|
168
|
+
}
|
169
|
+
|
170
|
+
//--------------------------------------------------------------------------
|
171
|
+
// Process maker note - to the limited extent that its supported.
|
172
|
+
//--------------------------------------------------------------------------
|
173
|
+
void ProcessMakerNote(unsigned char * ValuePtr, int ByteCount,
|
174
|
+
unsigned char * OffsetBase, unsigned ExifLength)
|
175
|
+
{
|
176
|
+
if (strstr(ImageInfo.CameraMake, "Canon")){
|
177
|
+
ProcessCanonMakerNoteDir(ValuePtr, OffsetBase, ExifLength);
|
178
|
+
}else{
|
179
|
+
if (ShowTags){
|
180
|
+
ShowMakerNoteGeneric(ValuePtr, ByteCount);
|
181
|
+
}
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
data/ext/myglob.c
ADDED
@@ -0,0 +1,305 @@
|
|
1
|
+
//--------------------------------------------------------------------------------
|
2
|
+
// Module to do recursive directory file matching under windows.
|
3
|
+
//
|
4
|
+
// Tries to do pattern matching to produce similar results as Unix, but using
|
5
|
+
// the Windows _findfirst to do all the pattern matching.
|
6
|
+
//
|
7
|
+
// Also hadles recursive directories - "**" path component expands into
|
8
|
+
// any levels of subdirectores (ie c:\**\*.c matches ALL .c files on drive c:)
|
9
|
+
//
|
10
|
+
// Matthias Wandel Nov 5 2000
|
11
|
+
//--------------------------------------------------------------------------------
|
12
|
+
#include <stdio.h>
|
13
|
+
#include <stdlib.h>
|
14
|
+
#include <string.h>
|
15
|
+
#include <errno.h>
|
16
|
+
#include <ctype.h>
|
17
|
+
#include <io.h>
|
18
|
+
#include "jhead.h"
|
19
|
+
|
20
|
+
#define TRUE 1
|
21
|
+
#define FALSE 0
|
22
|
+
|
23
|
+
//#define DEBUGGING
|
24
|
+
|
25
|
+
typedef struct {
|
26
|
+
char * Name;
|
27
|
+
int attrib;
|
28
|
+
}FileEntry;
|
29
|
+
|
30
|
+
|
31
|
+
#ifdef DEBUGGING
|
32
|
+
//--------------------------------------------------------------------------------
|
33
|
+
// Dummy function to show operation.
|
34
|
+
//--------------------------------------------------------------------------------
|
35
|
+
void ShowName(const char * FileName)
|
36
|
+
{
|
37
|
+
printf(" %s\n",FileName);
|
38
|
+
}
|
39
|
+
#endif
|
40
|
+
|
41
|
+
//--------------------------------------------------------------------------------
|
42
|
+
// Simple path splicing (assumes no '\' in either part)
|
43
|
+
//--------------------------------------------------------------------------------
|
44
|
+
static void SplicePath(char * dest, const char * p1, const char * p2)
|
45
|
+
{
|
46
|
+
int l;
|
47
|
+
l = strlen(p1);
|
48
|
+
if (!l){
|
49
|
+
strcpy(dest, p2);
|
50
|
+
}else{
|
51
|
+
if (l+strlen(p2) > _MAX_PATH-2){
|
52
|
+
fprintf(stderr,"Path too long\n");
|
53
|
+
exit(-1);
|
54
|
+
}
|
55
|
+
memcpy(dest, p1, l+1);
|
56
|
+
if (dest[l-1] != '\\' && dest[l-1] != ':'){
|
57
|
+
dest[l++] = '\\';
|
58
|
+
}
|
59
|
+
strcpy(dest+l, p2);
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
//--------------------------------------------------------------------------------
|
64
|
+
// Qsort compare function
|
65
|
+
//--------------------------------------------------------------------------------
|
66
|
+
int CompareFunc(const void * f1, const void * f2)
|
67
|
+
{
|
68
|
+
return strcmp(((FileEntry *)f1)->Name,((FileEntry *)f2)->Name);
|
69
|
+
}
|
70
|
+
|
71
|
+
//--------------------------------------------------------------------------------
|
72
|
+
// Decide how a particular pattern should be handled, and call function for each.
|
73
|
+
//--------------------------------------------------------------------------------
|
74
|
+
void MyGlob(const char * Pattern , void (*FileFuncParm)(const char * FileName))
|
75
|
+
{
|
76
|
+
char BasePattern[_MAX_PATH];
|
77
|
+
char MatchPattern[_MAX_PATH];
|
78
|
+
char PatCopy[_MAX_PATH*2+1];
|
79
|
+
|
80
|
+
int a;
|
81
|
+
|
82
|
+
int MatchFiles, MatchDirs;
|
83
|
+
int BaseEnd, PatternEnd;
|
84
|
+
int SawPat;
|
85
|
+
int RecurseAt;
|
86
|
+
|
87
|
+
strcpy(PatCopy, Pattern);
|
88
|
+
|
89
|
+
#ifdef DEBUGGING
|
90
|
+
printf("Called with '%s'\n",Pattern);
|
91
|
+
#endif
|
92
|
+
|
93
|
+
DoRecursion:
|
94
|
+
MatchFiles = FALSE;
|
95
|
+
MatchDirs = TRUE;
|
96
|
+
BaseEnd = 0;
|
97
|
+
PatternEnd = 0;
|
98
|
+
|
99
|
+
SawPat = FALSE;
|
100
|
+
RecurseAt = -1;
|
101
|
+
|
102
|
+
// Split the path into base path and pattern to match against using findfirst.
|
103
|
+
for (a=0;;a++){
|
104
|
+
if (PatCopy[a] == '*' || PatCopy[a] == '?'){
|
105
|
+
SawPat = TRUE;
|
106
|
+
}
|
107
|
+
|
108
|
+
if (PatCopy[a] == '*' && PatCopy[a+1] == '*'){
|
109
|
+
if (a == 0 || PatCopy[a-1] == '\\' || PatCopy[a-1] == ':'){
|
110
|
+
if (PatCopy[a+2] == '\\' || PatCopy[a+2] == '\0'){
|
111
|
+
// x\**\y ---> x\y x\*\**\y
|
112
|
+
RecurseAt = a;
|
113
|
+
if (PatCopy[a+2]){
|
114
|
+
memcpy(PatCopy+a, PatCopy+a+3, strlen(PatCopy)-a-1);
|
115
|
+
}else{
|
116
|
+
PatCopy[a+1] = '\0';
|
117
|
+
}
|
118
|
+
}
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
if (PatCopy[a] == '\\' || (PatCopy[a] == ':' && PatCopy[a+1] != '\\')){
|
123
|
+
PatternEnd = a;
|
124
|
+
if (SawPat) break; // Findfirst can only match one level of wildcard at a time.
|
125
|
+
BaseEnd = a+1;
|
126
|
+
}
|
127
|
+
if (PatCopy[a] == '\0'){
|
128
|
+
PatternEnd = a;
|
129
|
+
MatchFiles = TRUE;
|
130
|
+
MatchDirs = FALSE;
|
131
|
+
break;
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
if (!SawPat){
|
136
|
+
// No pattern. This should refer to a file.
|
137
|
+
FileFuncParm(PatCopy);
|
138
|
+
return;
|
139
|
+
}
|
140
|
+
|
141
|
+
strncpy(BasePattern, PatCopy, BaseEnd);
|
142
|
+
BasePattern[BaseEnd] = 0;
|
143
|
+
|
144
|
+
strncpy(MatchPattern, PatCopy, PatternEnd);
|
145
|
+
MatchPattern[PatternEnd] = 0;
|
146
|
+
|
147
|
+
#ifdef DEBUGGING
|
148
|
+
printf("Base:%s Pattern:%s Files:%d dirs:%d\n",BasePattern, MatchPattern, MatchFiles, MatchDirs);
|
149
|
+
#endif
|
150
|
+
|
151
|
+
{
|
152
|
+
FileEntry * FileList = NULL;
|
153
|
+
int NumAllocated = 0;
|
154
|
+
int NumHave = 0;
|
155
|
+
|
156
|
+
struct _finddata_t finddata;
|
157
|
+
long find_handle;
|
158
|
+
|
159
|
+
find_handle = _findfirst(MatchPattern, &finddata);
|
160
|
+
|
161
|
+
for (;;){
|
162
|
+
if (find_handle == -1) break;
|
163
|
+
|
164
|
+
// Eliminate the obvious patterns.
|
165
|
+
if (!memcmp(finddata.name, ".",2)) goto next_file;
|
166
|
+
if (!memcmp(finddata.name, "..",3)) goto next_file;
|
167
|
+
|
168
|
+
if (finddata.attrib & _A_SUBDIR){
|
169
|
+
if (!MatchDirs) goto next_file;
|
170
|
+
}else{
|
171
|
+
if (!MatchFiles) goto next_file;
|
172
|
+
}
|
173
|
+
|
174
|
+
// Add it to the list.
|
175
|
+
if (NumAllocated <= NumHave){
|
176
|
+
NumAllocated = NumAllocated+10+NumAllocated/2;
|
177
|
+
FileList = realloc(FileList, NumAllocated * sizeof(FileEntry));
|
178
|
+
if (FileList == NULL) goto nomem;
|
179
|
+
}
|
180
|
+
a = strlen(finddata.name);
|
181
|
+
FileList[NumHave].Name = malloc(a+1);
|
182
|
+
if (FileList[NumHave].Name == NULL){
|
183
|
+
nomem:
|
184
|
+
printf("malloc failure\n");
|
185
|
+
exit(-1);
|
186
|
+
}
|
187
|
+
memcpy(FileList[NumHave].Name, finddata.name, a+1);
|
188
|
+
FileList[NumHave].attrib = finddata.attrib;
|
189
|
+
NumHave++;
|
190
|
+
|
191
|
+
next_file:
|
192
|
+
if (_findnext(find_handle, &finddata) != 0) break;
|
193
|
+
}
|
194
|
+
_findclose(find_handle);
|
195
|
+
|
196
|
+
// Sort the list...
|
197
|
+
qsort(FileList, NumHave, sizeof(FileEntry), CompareFunc);
|
198
|
+
|
199
|
+
|
200
|
+
// Use the list.
|
201
|
+
for (a=0;a<NumHave;a++){
|
202
|
+
char CombinedName[_MAX_PATH*2+1];
|
203
|
+
if (FileList[a].attrib & _A_SUBDIR){
|
204
|
+
if (MatchDirs){
|
205
|
+
// Need more directories.
|
206
|
+
SplicePath(CombinedName, BasePattern, FileList[a].Name);
|
207
|
+
strncat(CombinedName, PatCopy+PatternEnd, _MAX_PATH*2-strlen(CombinedName));
|
208
|
+
MyGlob(CombinedName,FileFuncParm);
|
209
|
+
}
|
210
|
+
}else{
|
211
|
+
if (MatchFiles){
|
212
|
+
// We need files at this level.
|
213
|
+
SplicePath(CombinedName, BasePattern, FileList[a].Name);
|
214
|
+
FileFuncParm(CombinedName);
|
215
|
+
}
|
216
|
+
}
|
217
|
+
free(FileList[a].Name);
|
218
|
+
}
|
219
|
+
free(FileList);
|
220
|
+
}
|
221
|
+
|
222
|
+
if(RecurseAt >= 0){
|
223
|
+
strcpy(MatchPattern, PatCopy+RecurseAt);
|
224
|
+
PatCopy[RecurseAt] = 0;
|
225
|
+
strncpy(PatCopy+RecurseAt, "*\\**\\", _MAX_PATH*2-RecurseAt);
|
226
|
+
strncat(PatCopy, MatchPattern, _MAX_PATH*2-strlen(PatCopy));
|
227
|
+
|
228
|
+
#ifdef DEBUGGING
|
229
|
+
printf("Recurse with '%s'\n",PatCopy);
|
230
|
+
#endif
|
231
|
+
|
232
|
+
// As this function context is no longer needed, we can just goto back
|
233
|
+
// to the top of it to avoid adding another context on the stack.
|
234
|
+
goto DoRecursion;
|
235
|
+
}
|
236
|
+
}
|
237
|
+
|
238
|
+
//--------------------------------------------------------------------------------
|
239
|
+
// Flip slashes to native OS representation (for Windows)
|
240
|
+
//--------------------------------------------------------------------------------
|
241
|
+
void SlashToNative(char * Path)
|
242
|
+
{
|
243
|
+
int a;
|
244
|
+
for (a=0;Path[a];a++){
|
245
|
+
if (Path[a] == '/') Path[a] = SLASH;
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
249
|
+
|
250
|
+
#ifdef DEBUGGING
|
251
|
+
//--------------------------------------------------------------------------------
|
252
|
+
// The main program.
|
253
|
+
//--------------------------------------------------------------------------------
|
254
|
+
int main (int argc, char **argv)
|
255
|
+
{
|
256
|
+
int argn;
|
257
|
+
char * arg;
|
258
|
+
int Subdirs = 0;
|
259
|
+
|
260
|
+
for (argn=1;argn<argc;argn++){
|
261
|
+
arg = argv[argn];
|
262
|
+
if (arg[0] != '-') break; // Filenames from here on.
|
263
|
+
if (!strcmp(arg,"-r")){
|
264
|
+
printf("do recursive\n");
|
265
|
+
Subdirs = 1;
|
266
|
+
}else{
|
267
|
+
fprintf(stderr, "Argument '%s' not understood\n",arg);
|
268
|
+
}
|
269
|
+
}
|
270
|
+
if (argn == argc){
|
271
|
+
fprintf(stderr,"Error: Must supply a file name\n");
|
272
|
+
}
|
273
|
+
|
274
|
+
for (;argn<argc;argn++){
|
275
|
+
MyGlob(argv[argn], ShowName);
|
276
|
+
}
|
277
|
+
return EXIT_SUCCESS;
|
278
|
+
}
|
279
|
+
#endif
|
280
|
+
|
281
|
+
/*
|
282
|
+
|
283
|
+
non-recursive test cases:
|
284
|
+
|
285
|
+
e:\make*\*
|
286
|
+
\make*\*
|
287
|
+
e:*\*.c
|
288
|
+
\*\*.c
|
289
|
+
\*
|
290
|
+
c:*.c
|
291
|
+
c:\*
|
292
|
+
..\*.c
|
293
|
+
|
294
|
+
|
295
|
+
recursive test cases:
|
296
|
+
**
|
297
|
+
**\*.c
|
298
|
+
c:\**\*.c
|
299
|
+
c:**\*.c
|
300
|
+
.\**
|
301
|
+
..\**
|
302
|
+
|
303
|
+
*/
|
304
|
+
|
305
|
+
|