|
1
|
/* |
|
2
|
** Copyright (c) 2025 D. Richard Hipp |
|
3
|
** |
|
4
|
** This program is free software; you can redistribute it and/or |
|
5
|
** modify it under the terms of the Simplified BSD License (also |
|
6
|
** known as the "2-Clause License" or "FreeBSD License".) |
|
7
|
|
|
8
|
** This program is distributed in the hope that it will be useful, |
|
9
|
** but without any warranty; without even the implied warranty of |
|
10
|
** merchantability or fitness for a particular purpose. |
|
11
|
** |
|
12
|
** Author contact information: |
|
13
|
** [email protected] |
|
14
|
** |
|
15
|
******************************************************************************* |
|
16
|
** |
|
17
|
** This file contains code used to implement "fossil system ..." command. |
|
18
|
** |
|
19
|
** Fossil is frequently used by people familiar with Unix but who must |
|
20
|
** sometimes also work on Windows systems. The "fossil sys ..." command |
|
21
|
** provides a few work-arounds for command unix command-line utilities to |
|
22
|
** help make development on Windows more habitable for long-time unix |
|
23
|
** users. The commands provided here are normally cheap substitutes to |
|
24
|
** their more feature-reach unix counterparts. But they are sufficient to |
|
25
|
** get the job done. |
|
26
|
** |
|
27
|
** This source code file is called "xsystem.c" with the 'x' up front because |
|
28
|
** if it were called "system.c", then makeheaders would generate a "system.h" |
|
29
|
** header file, and that might be confused with an actual system header |
|
30
|
** file. |
|
31
|
*/ |
|
32
|
#include "config.h" |
|
33
|
#include "xsystem.h" |
|
34
|
#include "qrf.h" |
|
35
|
#include <time.h> |
|
36
|
#ifdef _WIN32 |
|
37
|
# include <windows.h> |
|
38
|
#endif |
|
39
|
|
|
40
|
|
|
41
|
/* Date and time */ |
|
42
|
void xsystem_date(int argc, char **argv){ |
|
43
|
(void)argc; |
|
44
|
(void)argv; |
|
45
|
fossil_print("%z = ", cgi_iso8601_datestamp()); |
|
46
|
fossil_print("%z\n", cgi_rfc822_datestamp(time(0))); |
|
47
|
} |
|
48
|
|
|
49
|
/* Present working directory */ |
|
50
|
void xsystem_pwd(int argc, char **argv){ |
|
51
|
char *zPwd = file_getcwd(0, 0); |
|
52
|
fossil_print("%z\n", zPwd); |
|
53
|
} |
|
54
|
|
|
55
|
/* Implement "stty size" */ |
|
56
|
void xsystem_stty(int argc, char **argv){ |
|
57
|
TerminalSize ts; |
|
58
|
if( argc!=2 || strcmp(argv[1],"size")!=0 ){ |
|
59
|
fossil_print("ERROR: only \"stty size\" is supported\n"); |
|
60
|
}else{ |
|
61
|
terminal_get_size(&ts); |
|
62
|
fossil_print("%d %d\n", ts.nLines, ts.nColumns); |
|
63
|
} |
|
64
|
} |
|
65
|
|
|
66
|
/* Show where an executable is located on PATH */ |
|
67
|
void xsystem_which(int argc, char **argv){ |
|
68
|
int ePrint = 1; |
|
69
|
int i; |
|
70
|
for(i=1; i<argc; i++){ |
|
71
|
const char *z = argv[i]; |
|
72
|
if( z[0]!='-' ){ |
|
73
|
fossil_app_on_path(z, ePrint); |
|
74
|
}else{ |
|
75
|
if( z[1]=='-' && z[2]!=0 ) z++; |
|
76
|
if( fossil_strcmp(z,"-a")==0 ){ |
|
77
|
ePrint = 2; |
|
78
|
}else |
|
79
|
{ |
|
80
|
fossil_fatal("unknown option \"%s\"", argv[i]); |
|
81
|
} |
|
82
|
} |
|
83
|
} |
|
84
|
} |
|
85
|
|
|
86
|
/* |
|
87
|
** Bit values for the mFlags paramater to "ls" |
|
88
|
*/ |
|
89
|
#define LS_LONG 0x001 /* -l Long format - one object per line */ |
|
90
|
#define LS_REVERSE 0x002 /* -r Reverse the sort order */ |
|
91
|
#define LS_MTIME 0x004 /* -t Sort by mtime, newest first */ |
|
92
|
#define LS_SIZE 0x008 /* -S Sort by size, largest first */ |
|
93
|
#define LS_COMMA 0x010 /* -m Comma-separated list */ |
|
94
|
#define LS_DIRONLY 0x020 /* -d Show just directory name, not content */ |
|
95
|
#define LS_ALL 0x040 /* -a Show all entries */ |
|
96
|
#define LS_COLOR 0x080 /* Colorize the output */ |
|
97
|
#define LS_COLUMNS 0x100 /* -C Split column output */ |
|
98
|
|
|
99
|
/* xWrite() callback from QRF |
|
100
|
*/ |
|
101
|
static int xsystem_write(void *NotUsed, const char *zText, sqlite3_int64 n){ |
|
102
|
fossil_puts(zText, 0, (int)n); |
|
103
|
return SQLITE_OK; |
|
104
|
} |
|
105
|
|
|
106
|
/* Helper function for xsystem_ls(): Make entries in the LS table |
|
107
|
** for every file or directory zName. |
|
108
|
** |
|
109
|
** If zName is a directory, load all files contained within that directory. |
|
110
|
** If zName is just a file, load only that file. |
|
111
|
*/ |
|
112
|
static void xsystem_ls_insert( |
|
113
|
sqlite3_stmt *pStmt, |
|
114
|
const char *zName, |
|
115
|
int mFlags |
|
116
|
){ |
|
117
|
char *aList[2]; |
|
118
|
char **azList; |
|
119
|
int nList; |
|
120
|
int i; |
|
121
|
const char *zPrefix; |
|
122
|
switch( file_isdir(zName, ExtFILE) ){ |
|
123
|
case 1: { /* A directory */ |
|
124
|
if( (mFlags & LS_DIRONLY)==0 ){ |
|
125
|
int omitDots = (mFlags & LS_ALL)!=0 ? 2 : 1; |
|
126
|
azList = 0; |
|
127
|
nList = file_directory_list(zName, 0, omitDots, 0, &azList); |
|
128
|
zPrefix = fossil_strcmp(zName,".") ? zName : 0; |
|
129
|
break; |
|
130
|
} |
|
131
|
} |
|
132
|
case 2: { /* A file */ |
|
133
|
aList[0] = (char*)zName; |
|
134
|
aList[1] = 0; |
|
135
|
azList = aList; |
|
136
|
nList = 1; |
|
137
|
zPrefix = 0; |
|
138
|
break; |
|
139
|
} |
|
140
|
default: { /* Does not exist */ |
|
141
|
return; |
|
142
|
} |
|
143
|
} |
|
144
|
for(i=0; i<nList; i++){ |
|
145
|
char *zFile = zPrefix ? mprintf("%s/%s",zPrefix,azList[i]) : azList[i]; |
|
146
|
int mode = file_mode(zFile, ExtFILE); |
|
147
|
sqlite3_int64 sz = file_size(zFile, ExtFILE); |
|
148
|
sqlite3_int64 mtime = file_mtime(zFile, ExtFILE); |
|
149
|
#ifdef _WIN32 |
|
150
|
if( (mFlags & LS_ALL)==0 ){ |
|
151
|
wchar_t *zMbcs = fossil_utf8_to_path(zFile, 1); |
|
152
|
DWORD attr = GetFileAttributesW(zMbcs); |
|
153
|
fossil_path_free(zMbcs); |
|
154
|
if( attr & FILE_ATTRIBUTE_HIDDEN ){ |
|
155
|
if( zPrefix ) fossil_free(zFile); |
|
156
|
continue; |
|
157
|
} |
|
158
|
} |
|
159
|
#endif |
|
160
|
sqlite3_bind_text(pStmt, 1, azList[i], -1, SQLITE_TRANSIENT); |
|
161
|
sqlite3_bind_int64(pStmt, 2, mtime); |
|
162
|
sqlite3_bind_int64(pStmt, 3, sz); |
|
163
|
sqlite3_bind_int(pStmt, 4, mode); |
|
164
|
sqlite3_bind_int64(pStmt, 5, strlen(zFile)); |
|
165
|
/* TODO: wcwidth()------^^^^^^ */ |
|
166
|
sqlite3_step(pStmt); |
|
167
|
sqlite3_reset(pStmt); |
|
168
|
if( zPrefix ) fossil_free(zFile); |
|
169
|
} |
|
170
|
if( azList!=aList ){ |
|
171
|
file_directory_list_free(azList); |
|
172
|
} |
|
173
|
} |
|
174
|
|
|
175
|
/* |
|
176
|
** Return arguments to ORDER BY that will correctly sort the entries. |
|
177
|
*/ |
|
178
|
static const char *xsystem_ls_orderby(int mFlags){ |
|
179
|
static const char *zSortTypes[] = { |
|
180
|
"fn COLLATE NOCASE", |
|
181
|
"mtime DESC", |
|
182
|
"size DESC", |
|
183
|
"fn COLLATE NOCASE DESC", |
|
184
|
"mtime", |
|
185
|
"size" |
|
186
|
}; |
|
187
|
int i = 0; |
|
188
|
if( mFlags & LS_MTIME ) i = 1; |
|
189
|
if( mFlags & LS_SIZE ) i = 2; |
|
190
|
if( mFlags & LS_REVERSE ) i += 3; |
|
191
|
return zSortTypes[i]; |
|
192
|
} |
|
193
|
|
|
194
|
/* |
|
195
|
** color(fn,mode) |
|
196
|
** |
|
197
|
** SQL function to colorize a filename based on its mode. |
|
198
|
*/ |
|
199
|
static void colorNameFunc( |
|
200
|
sqlite3_context *context, |
|
201
|
int argc, |
|
202
|
sqlite3_value **argv |
|
203
|
){ |
|
204
|
const char *zName = (const char*)sqlite3_value_text(argv[0]); |
|
205
|
int iMode = sqlite3_value_int(argv[1]); |
|
206
|
sqlite3_str *pOut; |
|
207
|
if( zName==0 ) return; |
|
208
|
pOut = sqlite3_str_new(0); |
|
209
|
#ifdef _WIN32 |
|
210
|
if( sqlite3_strlike("%.exe",zName,0)==0 ) iMode |= 0111; |
|
211
|
#endif |
|
212
|
if( iMode & 040000 ){ |
|
213
|
/* A directory */ |
|
214
|
sqlite3_str_appendall(pOut, "\033[1;34m"); |
|
215
|
}else if( iMode & 0100 ){ |
|
216
|
/* Executable */ |
|
217
|
sqlite3_str_appendall(pOut, "\033[1;32m"); |
|
218
|
} |
|
219
|
sqlite3_str_appendall(pOut, zName); |
|
220
|
if( (iMode & 040100)!=0 ){ |
|
221
|
sqlite3_str_appendall(pOut, "\033[0m"); |
|
222
|
} |
|
223
|
sqlite3_result_text(context, sqlite3_str_value(pOut), -1, SQLITE_TRANSIENT); |
|
224
|
sqlite3_str_free(pOut); |
|
225
|
} |
|
226
|
/* Alternative implementation that does *not* introduce color */ |
|
227
|
static void nocolorNameFunc( |
|
228
|
sqlite3_context *context, |
|
229
|
int argc, |
|
230
|
sqlite3_value **argv |
|
231
|
){ |
|
232
|
sqlite3_result_value(context, argv[0]); |
|
233
|
} |
|
234
|
|
|
235
|
|
|
236
|
|
|
237
|
/* |
|
238
|
** Show ls output information for content in the LS table |
|
239
|
*/ |
|
240
|
static void xsystem_ls_render( |
|
241
|
sqlite3 *db, |
|
242
|
int mFlags |
|
243
|
){ |
|
244
|
sqlite3_stmt *pStmt; |
|
245
|
if( mFlags & LS_COLOR ){ |
|
246
|
sqlite3_create_function(db, "color",2,SQLITE_UTF8,0,colorNameFunc,0,0); |
|
247
|
}else{ |
|
248
|
sqlite3_create_function(db, "color",2,SQLITE_UTF8,0,nocolorNameFunc,0,0); |
|
249
|
} |
|
250
|
if( (mFlags & LS_LONG)!=0 ){ |
|
251
|
/* Long mode */ |
|
252
|
char *zSql; |
|
253
|
int szSz = 8; |
|
254
|
sqlite3_prepare_v2(db, "SELECT length(max(size)) FROM ls", -1, &pStmt, 0); |
|
255
|
if( sqlite3_step(pStmt)==SQLITE_ROW ){ |
|
256
|
szSz = sqlite3_column_int(pStmt, 0); |
|
257
|
} |
|
258
|
sqlite3_finalize(pStmt); |
|
259
|
pStmt = 0; |
|
260
|
zSql = mprintf( |
|
261
|
"SELECT mode, size, datetime(mtime,'unixepoch'), color(fn,mode)" |
|
262
|
" FROM ls ORDER BY %s", |
|
263
|
xsystem_ls_orderby(mFlags)); |
|
264
|
sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); |
|
265
|
while( sqlite3_step(pStmt)==SQLITE_ROW ){ |
|
266
|
char zMode[12]; |
|
267
|
const char *zName = (const char*)sqlite3_column_text(pStmt, 3); |
|
268
|
int mode = sqlite3_column_int(pStmt, 0); |
|
269
|
#ifdef _WIN32 |
|
270
|
memcpy(zMode, "-rw-", 5); |
|
271
|
if( mode & 040000 ){ |
|
272
|
zMode[0] = 'd'; |
|
273
|
zMode[3] = 'x'; |
|
274
|
}else if( sqlite3_strlike("%.EXE",zName,0)==0 ){ |
|
275
|
zMode[3] = 'x'; |
|
276
|
} |
|
277
|
#else |
|
278
|
memcpy(zMode, "----------", 11); |
|
279
|
if( mode & 040000 ) zMode[0] = 'd'; |
|
280
|
if( mode & 0400 ) zMode[1] = 'r'; |
|
281
|
if( mode & 0200 ) zMode[2] = 'w'; |
|
282
|
if( mode & 0100 ) zMode[3] = 'x'; |
|
283
|
if( mode & 0040 ) zMode[4] = 'r'; |
|
284
|
if( mode & 0020 ) zMode[5] = 'w'; |
|
285
|
if( mode & 0010 ) zMode[6] = 'x'; |
|
286
|
if( mode & 0004 ) zMode[7] = 'r'; |
|
287
|
if( mode & 0002 ) zMode[8] = 'w'; |
|
288
|
if( mode & 0001 ) zMode[9] = 'x'; |
|
289
|
#endif |
|
290
|
fossil_print("%s %*lld %s %s\n", |
|
291
|
zMode, |
|
292
|
szSz, |
|
293
|
sqlite3_column_int64(pStmt, 1), |
|
294
|
sqlite3_column_text(pStmt, 2), |
|
295
|
zName); |
|
296
|
} |
|
297
|
sqlite3_finalize(pStmt); |
|
298
|
}else if( (mFlags & LS_COMMA)!=0 ){ |
|
299
|
/* Comma-separate list */ |
|
300
|
int mx = terminal_get_width(80); |
|
301
|
int sumW = 0; |
|
302
|
char *zSql; |
|
303
|
zSql = mprintf("SELECT color(fn,mode), dlen FROM ls ORDER BY %s", |
|
304
|
xsystem_ls_orderby(mFlags)); |
|
305
|
sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); |
|
306
|
while( sqlite3_step(pStmt)==SQLITE_ROW ){ |
|
307
|
const char *z = (const char*)sqlite3_column_text(pStmt, 0); |
|
308
|
int w = sqlite3_column_int(pStmt, 1); |
|
309
|
if( sumW==0 ){ |
|
310
|
fossil_print("%s", z); |
|
311
|
sumW = w; |
|
312
|
}else if( sumW + w + 2 >= mx ){ |
|
313
|
fossil_print("\n%s", z); |
|
314
|
sumW = w; |
|
315
|
}else{ |
|
316
|
fossil_print(", %s", z); |
|
317
|
sumW += w+2; |
|
318
|
} |
|
319
|
} |
|
320
|
fossil_free(zSql); |
|
321
|
sqlite3_finalize(pStmt); |
|
322
|
if( sumW>0 ) fossil_print("\n"); |
|
323
|
}else{ |
|
324
|
/* Column mode with just filenames */ |
|
325
|
sqlite3_qrf_spec spec; |
|
326
|
char *zSql; |
|
327
|
memset(&spec, 0, sizeof(spec)); |
|
328
|
spec.iVersion = 1; |
|
329
|
spec.xWrite = xsystem_write; |
|
330
|
spec.eStyle = QRF_STYLE_Column; |
|
331
|
spec.bTitles = QRF_No; |
|
332
|
spec.eEsc = QRF_No; |
|
333
|
if( mFlags & LS_COLUMNS ){ |
|
334
|
spec.nScreenWidth = terminal_get_width(80); |
|
335
|
spec.bSplitColumn = QRF_Yes; |
|
336
|
} |
|
337
|
zSql = mprintf("SELECT color(fn,mode) FROM ls ORDER BY %s", |
|
338
|
xsystem_ls_orderby(mFlags)); |
|
339
|
sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); |
|
340
|
fossil_free(zSql); |
|
341
|
sqlite3_format_query_result(pStmt, &spec, 0); |
|
342
|
sqlite3_finalize(pStmt); |
|
343
|
} |
|
344
|
sqlite3_exec(db, "DELETE FROM ls;", 0, 0, 0); |
|
345
|
} |
|
346
|
|
|
347
|
/* List files "ls" |
|
348
|
** Options: |
|
349
|
** |
|
350
|
** -a Show files that begin with "." |
|
351
|
** -C List by columns |
|
352
|
** --color=WHEN Colorize output? |
|
353
|
** -d Show just directory names, not content |
|
354
|
** -l Long listing |
|
355
|
** -m Comma-separated list |
|
356
|
** -r Reverse sort |
|
357
|
** -S Sort by size, largest first |
|
358
|
** -t Sort by mtime, newest first |
|
359
|
*/ |
|
360
|
void xsystem_ls(int argc, char **argv){ |
|
361
|
int i, rc; |
|
362
|
sqlite3 *db; |
|
363
|
sqlite3_stmt *pStmt = 0; |
|
364
|
int mFlags = 0; |
|
365
|
int nFile = 0; |
|
366
|
int nDir = 0; |
|
367
|
int bAutoColor = 1; |
|
368
|
int needBlankLine = 0; |
|
369
|
rc = sqlite3_open(":memory:", &db); |
|
370
|
if( rc || db==0 ){ |
|
371
|
fossil_fatal("Cannot open in-memory database"); |
|
372
|
} |
|
373
|
sqlite3_exec(db, "CREATE TABLE ls(fn,mtime,size,mode,dlen);", 0,0,0); |
|
374
|
rc = sqlite3_prepare_v2(db, "INSERT INTO ls VALUES(?1,?2,?3,?4,?5)", |
|
375
|
-1, &pStmt, 0); |
|
376
|
if( rc || db==0 ){ |
|
377
|
fossil_fatal("Cannot prepare INSERT statement"); |
|
378
|
} |
|
379
|
for(i=1; i<argc; i++){ |
|
380
|
const char *z = argv[i]; |
|
381
|
if( z[0]=='-' ){ |
|
382
|
if( z[1]=='-' ){ |
|
383
|
if( strncmp(z,"--color",7)==0 ){ |
|
384
|
if( z[7]==0 || strcmp(&z[7],"=always")==0 ){ |
|
385
|
mFlags |= LS_COLOR; |
|
386
|
}else if( strcmp(&z[7],"=never")==0 ){ |
|
387
|
bAutoColor = 0; |
|
388
|
} |
|
389
|
}else{ |
|
390
|
fossil_fatal("unknown option: %s", z); |
|
391
|
} |
|
392
|
}else{ |
|
393
|
int k; |
|
394
|
for(k=1; z[k]; k++){ |
|
395
|
switch( z[k] ){ |
|
396
|
case 'a': mFlags |= LS_ALL; break; |
|
397
|
case 'd': mFlags |= LS_DIRONLY; break; |
|
398
|
case 'l': mFlags |= LS_LONG; break; |
|
399
|
case 'm': mFlags |= LS_COMMA; break; |
|
400
|
case 'r': mFlags |= LS_REVERSE; break; |
|
401
|
case 'S': mFlags |= LS_SIZE; break; |
|
402
|
case 't': mFlags |= LS_MTIME; break; |
|
403
|
case 'C': mFlags |= LS_COLUMNS; break; |
|
404
|
default: { |
|
405
|
fossil_fatal("unknown option: -%c", z[k]); |
|
406
|
} |
|
407
|
} |
|
408
|
} |
|
409
|
} |
|
410
|
}else{ |
|
411
|
if( (mFlags & LS_DIRONLY)==0 && file_isdir(z, ExtFILE)==1 ){ |
|
412
|
nDir++; |
|
413
|
}else{ |
|
414
|
nFile++; |
|
415
|
xsystem_ls_insert(pStmt, z, mFlags); |
|
416
|
} |
|
417
|
} |
|
418
|
} |
|
419
|
if( fossil_isatty(1) ){ |
|
420
|
if( bAutoColor ) mFlags |= LS_COLOR; |
|
421
|
mFlags |= LS_COLUMNS; |
|
422
|
} |
|
423
|
if( nFile>0 ){ |
|
424
|
xsystem_ls_render(db, mFlags); |
|
425
|
needBlankLine = 1; |
|
426
|
}else if( nDir==0 ){ |
|
427
|
xsystem_ls_insert(pStmt, ".", mFlags); |
|
428
|
xsystem_ls_render(db, mFlags); |
|
429
|
} |
|
430
|
if( nDir>0 ){ |
|
431
|
for(i=1; i<argc; i++){ |
|
432
|
const char *z = argv[i]; |
|
433
|
if( z[0]=='-' ) continue; |
|
434
|
if( file_isdir(z, ExtFILE)!=1 ) continue; |
|
435
|
if( needBlankLine ){ |
|
436
|
fossil_print("\n"); |
|
437
|
needBlankLine = 0; |
|
438
|
} |
|
439
|
fossil_print("%s:\n", z); |
|
440
|
xsystem_ls_insert(pStmt, z, mFlags); |
|
441
|
xsystem_ls_render(db, mFlags); |
|
442
|
} |
|
443
|
} |
|
444
|
sqlite3_finalize(pStmt); |
|
445
|
sqlite3_close(db); |
|
446
|
} |
|
447
|
|
|
448
|
/* |
|
449
|
** unzip [-l] ZIPFILE |
|
450
|
*/ |
|
451
|
void xsystem_unzip(int argc, char **argv){ |
|
452
|
const char *zZipfile = 0; |
|
453
|
int doList = 0; |
|
454
|
int i; |
|
455
|
char *a[5]; |
|
456
|
int n; |
|
457
|
extern int sqlite3_shell(int, char**); |
|
458
|
|
|
459
|
for(i=1; i<argc; i++){ |
|
460
|
const char *z = argv[i]; |
|
461
|
if( z[0]=='-' ){ |
|
462
|
if( z[1]=='-' && z[2]!=0 ) z++; |
|
463
|
if( strcmp(z,"-l")==0 ){ |
|
464
|
doList = 1; |
|
465
|
}else |
|
466
|
{ |
|
467
|
fossil_fatal("unknown option: %s", argv[i]); |
|
468
|
} |
|
469
|
}else if( zZipfile!=0 ){ |
|
470
|
fossil_fatal("extra argument: %s", z); |
|
471
|
}else{ |
|
472
|
zZipfile = z; |
|
473
|
} |
|
474
|
} |
|
475
|
if( zZipfile==0 ){ |
|
476
|
fossil_fatal("Usage: fossil sys unzip [-l] ZIPFILE"); |
|
477
|
}else if( file_size(zZipfile, ExtFILE)<0 ){ |
|
478
|
fossil_fatal("No such file: %s\n", zZipfile); |
|
479
|
} |
|
480
|
g.zRepositoryName = 0; |
|
481
|
g.zLocalDbName = 0; |
|
482
|
g.zConfigDbName = 0; |
|
483
|
sqlite3_shutdown(); |
|
484
|
a[0] = argv[0]; |
|
485
|
a[1] = (char*)zZipfile; |
|
486
|
if( doList ){ |
|
487
|
a[2] = ".mode column"; |
|
488
|
a[3] = "SELECT sz AS Size, date(mtime,'unixepoch') AS Date," |
|
489
|
" time(mtime,'unixepoch') AS Time," |
|
490
|
" if(((mode>>12)&15)=10,name||' -> '||data,name) AS Name" |
|
491
|
" FROM zip;"; |
|
492
|
n = 4; |
|
493
|
}else{ |
|
494
|
a[2] = ".mode list"; |
|
495
|
a[3] = "SELECT if(((mode>>12)&15)==10,'symlink-ignored: '||name," |
|
496
|
"writefile(name,data,mode,mtime) IS NULL," |
|
497
|
"'error: '||name,'extracting: '||name) FROM zip"; |
|
498
|
n = 4; |
|
499
|
} |
|
500
|
a[n] = 0; |
|
501
|
sqlite3_shell(n,a); |
|
502
|
} |
|
503
|
|
|
504
|
/* |
|
505
|
** zip [OPTIONS] ZIPFILE FILE ... |
|
506
|
*/ |
|
507
|
void xsystem_zip(int argc, char **argv){ |
|
508
|
int i; |
|
509
|
for(i=0; i<argc; i++){ |
|
510
|
g.argv[i+1] = argv[i]; |
|
511
|
} |
|
512
|
g.argc = argc+1; |
|
513
|
filezip_cmd(); |
|
514
|
} |
|
515
|
|
|
516
|
/* |
|
517
|
** Available system commands. |
|
518
|
*/ |
|
519
|
typedef struct XSysCmd XSysCmd; |
|
520
|
static struct XSysCmd { |
|
521
|
const char *zName; |
|
522
|
void (*xFunc)(int,char**); |
|
523
|
const char *zHelp; |
|
524
|
} aXSysCmd[] = { |
|
525
|
{ "date", xsystem_date, |
|
526
|
"\n" |
|
527
|
"Show the current system time and date\n" |
|
528
|
}, |
|
529
|
{ "ls", xsystem_ls, |
|
530
|
"[OPTIONS] [PATH] ...\n" |
|
531
|
"Options:\n" |
|
532
|
" -a Show files that begin with '.'\n" |
|
533
|
" -C Split columns\n" |
|
534
|
" -d Show just directory names, not content\n" |
|
535
|
" -l Long listing\n" |
|
536
|
" -m Comma-separated list\n" |
|
537
|
" -r Reverse sort order\n" |
|
538
|
" -S Sort by size, largest first\n" |
|
539
|
" -t Sort by mtime, newest first\n" |
|
540
|
" --color[=WHEN] Colorize output?\n" |
|
541
|
}, |
|
542
|
{ "pwd", xsystem_pwd, |
|
543
|
"\n" |
|
544
|
"Show the Present Working Directory name\n" |
|
545
|
}, |
|
546
|
{ "stty", xsystem_stty, |
|
547
|
"\n" |
|
548
|
"Show the size of the TTY\n" |
|
549
|
}, |
|
550
|
{ "unzip", xsystem_unzip, |
|
551
|
"[-l] ZIPFILE\n\n" |
|
552
|
"Extract content from ZIPFILE, or list the content if the -l option\n" |
|
553
|
"is used.\n" |
|
554
|
}, |
|
555
|
{ "which", xsystem_which, |
|
556
|
"EXE ...\n" |
|
557
|
"Show the location on PATH of executables EXE\n" |
|
558
|
"Options:\n" |
|
559
|
" -a Show all path locations rather than just the first\n" |
|
560
|
}, |
|
561
|
{ "zip", xsystem_zip, |
|
562
|
"ZIPFILE FILE ...\n\n" |
|
563
|
"Create a new ZIP archive named ZIPFILE using listed files as content\n" |
|
564
|
}, |
|
565
|
}; |
|
566
|
|
|
567
|
/* |
|
568
|
** COMMAND: system |
|
569
|
** |
|
570
|
** Usage: %fossil system COMMAND ARGS... |
|
571
|
** |
|
572
|
** Often abbreviated as just "fossil sys", this command provides primitive, |
|
573
|
** low-level unix-like commands for use on systems that lack those commands |
|
574
|
** natively. |
|
575
|
** |
|
576
|
** Type "fossil sys help" for a list of available commands. |
|
577
|
** |
|
578
|
** Type "fossil sys help COMMAND" for detailed help on a particular |
|
579
|
** command. |
|
580
|
*/ |
|
581
|
void xsystem_cmd(void){ |
|
582
|
int i; |
|
583
|
const char *zCmd; |
|
584
|
int bHelp = 0; |
|
585
|
if( g.argc<=2 || (g.argc==3 && fossil_strcmp(g.argv[2],"help")==0) ){ |
|
586
|
fossil_print("Available commands:\n"); |
|
587
|
for(i=0; i<count(aXSysCmd); i++){ |
|
588
|
if( (i%4)==3 || i==count(aXSysCmd)-1 ){ |
|
589
|
fossil_print(" %s\n", aXSysCmd[i].zName); |
|
590
|
}else{ |
|
591
|
fossil_print(" %-12s", aXSysCmd[i].zName); |
|
592
|
} |
|
593
|
} |
|
594
|
return; |
|
595
|
} |
|
596
|
zCmd = g.argv[2]; |
|
597
|
if( fossil_strcmp(zCmd, "help")==0 ){ |
|
598
|
bHelp = 1; |
|
599
|
zCmd = g.argv[3]; |
|
600
|
} |
|
601
|
for(i=0; i<count(aXSysCmd); i++){ |
|
602
|
if( fossil_strcmp(zCmd,aXSysCmd[i].zName)==0 ){ |
|
603
|
if( !bHelp ){ |
|
604
|
aXSysCmd[i].xFunc(g.argc-2, g.argv+2); |
|
605
|
}else{ |
|
606
|
fossil_print("Usage: fossil system %s %s", zCmd, aXSysCmd[i].zHelp); |
|
607
|
} |
|
608
|
return; |
|
609
|
} |
|
610
|
} |
|
611
|
fossil_fatal("Unknown system command \"%s\"." |
|
612
|
" Use \"%s system help\" for a list of available commands", |
|
613
|
zCmd, g.argv[0]); |
|
614
|
} |
|
615
|
|