13
13
#include "userdiff.h"
14
14
#include "streaming.h"
15
15
16
- #define BATCH 1
17
- #define BATCH_CHECK 2
18
-
19
16
static int cat_one_file (int opt , const char * exp_type , const char * obj_name )
20
17
{
21
18
unsigned char sha1 [20 ];
@@ -117,54 +114,174 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
117
114
return 0 ;
118
115
}
119
116
120
- static int batch_one_object (const char * obj_name , int print_contents )
121
- {
117
+ struct expand_data {
122
118
unsigned char sha1 [20 ];
123
- enum object_type type = 0 ;
119
+ enum object_type type ;
124
120
unsigned long size ;
125
- void * contents = NULL ;
121
+ unsigned long disk_size ;
122
+ const char * rest ;
123
+
124
+ /*
125
+ * If mark_query is true, we do not expand anything, but rather
126
+ * just mark the object_info with items we wish to query.
127
+ */
128
+ int mark_query ;
129
+
130
+ /*
131
+ * After a mark_query run, this object_info is set up to be
132
+ * passed to sha1_object_info_extended. It will point to the data
133
+ * elements above, so you can retrieve the response from there.
134
+ */
135
+ struct object_info info ;
136
+ };
137
+
138
+ static int is_atom (const char * atom , const char * s , int slen )
139
+ {
140
+ int alen = strlen (atom );
141
+ return alen == slen && !memcmp (atom , s , alen );
142
+ }
143
+
144
+ static void expand_atom (struct strbuf * sb , const char * atom , int len ,
145
+ void * vdata )
146
+ {
147
+ struct expand_data * data = vdata ;
148
+
149
+ if (is_atom ("objectname" , atom , len )) {
150
+ if (!data -> mark_query )
151
+ strbuf_addstr (sb , sha1_to_hex (data -> sha1 ));
152
+ } else if (is_atom ("objecttype" , atom , len )) {
153
+ if (!data -> mark_query )
154
+ strbuf_addstr (sb , typename (data -> type ));
155
+ } else if (is_atom ("objectsize" , atom , len )) {
156
+ if (data -> mark_query )
157
+ data -> info .sizep = & data -> size ;
158
+ else
159
+ strbuf_addf (sb , "%lu" , data -> size );
160
+ } else if (is_atom ("objectsize:disk" , atom , len )) {
161
+ if (data -> mark_query )
162
+ data -> info .disk_sizep = & data -> disk_size ;
163
+ else
164
+ strbuf_addf (sb , "%lu" , data -> disk_size );
165
+ } else if (is_atom ("rest" , atom , len )) {
166
+ if (!data -> mark_query && data -> rest )
167
+ strbuf_addstr (sb , data -> rest );
168
+ } else
169
+ die ("unknown format element: %.*s" , len , atom );
170
+ }
171
+
172
+ static size_t expand_format (struct strbuf * sb , const char * start , void * data )
173
+ {
174
+ const char * end ;
175
+
176
+ if (* start != '(' )
177
+ return 0 ;
178
+ end = strchr (start + 1 , ')' );
179
+ if (!end )
180
+ die ("format element '%s' does not end in ')'" , start );
181
+
182
+ expand_atom (sb , start + 1 , end - start - 1 , data );
183
+
184
+ return end - start + 1 ;
185
+ }
186
+
187
+ static void print_object_or_die (int fd , const unsigned char * sha1 ,
188
+ enum object_type type , unsigned long size )
189
+ {
190
+ if (type == OBJ_BLOB ) {
191
+ if (stream_blob_to_fd (fd , sha1 , NULL , 0 ) < 0 )
192
+ die ("unable to stream %s to stdout" , sha1_to_hex (sha1 ));
193
+ }
194
+ else {
195
+ enum object_type rtype ;
196
+ unsigned long rsize ;
197
+ void * contents ;
198
+
199
+ contents = read_sha1_file (sha1 , & rtype , & rsize );
200
+ if (!contents )
201
+ die ("object %s disappeared" , sha1_to_hex (sha1 ));
202
+ if (rtype != type )
203
+ die ("object %s changed type!?" , sha1_to_hex (sha1 ));
204
+ if (rsize != size )
205
+ die ("object %s change size!?" , sha1_to_hex (sha1 ));
206
+
207
+ write_or_die (fd , contents , size );
208
+ free (contents );
209
+ }
210
+ }
211
+
212
+ struct batch_options {
213
+ int enabled ;
214
+ int print_contents ;
215
+ const char * format ;
216
+ };
217
+
218
+ static int batch_one_object (const char * obj_name , struct batch_options * opt ,
219
+ struct expand_data * data )
220
+ {
221
+ struct strbuf buf = STRBUF_INIT ;
126
222
127
223
if (!obj_name )
128
224
return 1 ;
129
225
130
- if (get_sha1 (obj_name , sha1 )) {
226
+ if (get_sha1 (obj_name , data -> sha1 )) {
131
227
printf ("%s missing\n" , obj_name );
132
228
fflush (stdout );
133
229
return 0 ;
134
230
}
135
231
136
- if (print_contents == BATCH )
137
- contents = read_sha1_file (sha1 , & type , & size );
138
- else
139
- type = sha1_object_info (sha1 , & size );
140
-
141
- if (type <= 0 ) {
232
+ data -> type = sha1_object_info_extended (data -> sha1 , & data -> info );
233
+ if (data -> type <= 0 ) {
142
234
printf ("%s missing\n" , obj_name );
143
235
fflush (stdout );
144
- if (print_contents == BATCH )
145
- free (contents );
146
236
return 0 ;
147
237
}
148
238
149
- printf ("%s %s %lu\n" , sha1_to_hex (sha1 ), typename (type ), size );
150
- fflush (stdout );
239
+ strbuf_expand (& buf , opt -> format , expand_format , data );
240
+ strbuf_addch (& buf , '\n' );
241
+ write_or_die (1 , buf .buf , buf .len );
242
+ strbuf_release (& buf );
151
243
152
- if (print_contents == BATCH ) {
153
- write_or_die (1 , contents , size );
154
- printf ("\n" );
155
- fflush (stdout );
156
- free (contents );
244
+ if (opt -> print_contents ) {
245
+ print_object_or_die (1 , data -> sha1 , data -> type , data -> size );
246
+ write_or_die (1 , "\n" , 1 );
157
247
}
158
-
159
248
return 0 ;
160
249
}
161
250
162
- static int batch_objects (int print_contents )
251
+ static int batch_objects (struct batch_options * opt )
163
252
{
164
253
struct strbuf buf = STRBUF_INIT ;
254
+ struct expand_data data ;
255
+
256
+ if (!opt -> format )
257
+ opt -> format = "%(objectname) %(objecttype) %(objectsize)" ;
258
+
259
+ /*
260
+ * Expand once with our special mark_query flag, which will prime the
261
+ * object_info to be handed to sha1_object_info_extended for each
262
+ * object.
263
+ */
264
+ memset (& data , 0 , sizeof (data ));
265
+ data .mark_query = 1 ;
266
+ strbuf_expand (& buf , opt -> format , expand_format , & data );
267
+ data .mark_query = 0 ;
165
268
166
269
while (strbuf_getline (& buf , stdin , '\n' ) != EOF ) {
167
- int error = batch_one_object (buf .buf , print_contents );
270
+ char * p ;
271
+ int error ;
272
+
273
+ /*
274
+ * Split at first whitespace, tying off the beginning of the
275
+ * string and saving the remainder (or NULL) in data.rest.
276
+ */
277
+ p = strpbrk (buf .buf , " \t" );
278
+ if (p ) {
279
+ while (* p && strchr (" \t" , * p ))
280
+ * p ++ = '\0' ;
281
+ }
282
+ data .rest = p ;
283
+
284
+ error = batch_one_object (buf .buf , opt , & data );
168
285
if (error )
169
286
return error ;
170
287
}
@@ -186,10 +303,29 @@ static int git_cat_file_config(const char *var, const char *value, void *cb)
186
303
return git_default_config (var , value , cb );
187
304
}
188
305
306
+ static int batch_option_callback (const struct option * opt ,
307
+ const char * arg ,
308
+ int unset )
309
+ {
310
+ struct batch_options * bo = opt -> value ;
311
+
312
+ if (unset ) {
313
+ memset (bo , 0 , sizeof (* bo ));
314
+ return 0 ;
315
+ }
316
+
317
+ bo -> enabled = 1 ;
318
+ bo -> print_contents = !strcmp (opt -> long_name , "batch" );
319
+ bo -> format = arg ;
320
+
321
+ return 0 ;
322
+ }
323
+
189
324
int cmd_cat_file (int argc , const char * * argv , const char * prefix )
190
325
{
191
- int opt = 0 , batch = 0 ;
326
+ int opt = 0 ;
192
327
const char * exp_type = NULL , * obj_name = NULL ;
328
+ struct batch_options batch = {0 };
193
329
194
330
const struct option options [] = {
195
331
OPT_GROUP (N_ ("<type> can be one of: blob, tree, commit, tag" )),
@@ -200,12 +336,12 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
200
336
OPT_SET_INT ('p' , NULL , & opt , N_ ("pretty-print object's content" ), 'p' ),
201
337
OPT_SET_INT (0 , "textconv" , & opt ,
202
338
N_ ("for blob objects, run textconv on object's content" ), 'c' ),
203
- OPT_SET_INT ( 0 , "batch" , & batch ,
204
- N_ ("show info and content of objects fed from the standard input" ),
205
- BATCH ) ,
206
- OPT_SET_INT ( 0 , "batch-check" , & batch ,
207
- N_ ("show info about objects fed from the standard input" ),
208
- BATCH_CHECK ) ,
339
+ { OPTION_CALLBACK , 0 , "batch" , & batch , "format" ,
340
+ N_ ("show info and content of objects fed from the standard input" ),
341
+ PARSE_OPT_OPTARG , batch_option_callback } ,
342
+ { OPTION_CALLBACK , 0 , "batch-check" , & batch , "format" ,
343
+ N_ ("show info about objects fed from the standard input" ),
344
+ PARSE_OPT_OPTARG , batch_option_callback } ,
209
345
OPT_END ()
210
346
};
211
347
@@ -222,19 +358,19 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
222
358
else
223
359
usage_with_options (cat_file_usage , options );
224
360
}
225
- if (!opt && !batch ) {
361
+ if (!opt && !batch . enabled ) {
226
362
if (argc == 2 ) {
227
363
exp_type = argv [0 ];
228
364
obj_name = argv [1 ];
229
365
} else
230
366
usage_with_options (cat_file_usage , options );
231
367
}
232
- if (batch && (opt || argc )) {
368
+ if (batch . enabled && (opt || argc )) {
233
369
usage_with_options (cat_file_usage , options );
234
370
}
235
371
236
- if (batch )
237
- return batch_objects (batch );
372
+ if (batch . enabled )
373
+ return batch_objects (& batch );
238
374
239
375
return cat_one_file (opt , exp_type , obj_name );
240
376
}
0 commit comments