Fossil SCM

fossil-scm / tools / skintxt2config.c
Blame History Raw 220 lines
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=2 et sw=2 tw=80: */
3
/*
4
** Copyright (c) 2021 Stephan Beal (https://wanderinghorse.net/home/stephan/)
5
**
6
** This program is free software; you can redistribute it and/or
7
** modify it under the terms of the Simplified BSD License (also
8
** known as the "2-Clause License" or "FreeBSD License".)
9
**
10
** This program is distributed in the hope that it will be useful,
11
** but without any warranty; without even the implied warranty of
12
** merchantability or fitness for a particular purpose.
13
**
14
*******************************************************************************
15
**
16
** This application reads in Fossil SCM skin configuration files and emits
17
** them in a form suitable for importing directly into a fossil database
18
** using the (fossil config import) command.
19
**
20
** As input it requires one or more skin configuration files (css.txt,
21
** header.txt, footer.txt, details.txt, js.txt) and all output goes to
22
** stdout unless redirected using the -o FILENAME flag.
23
**
24
** Run it with no arguments or one of (help, --help, -?) for help text.
25
*/
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <errno.h>
30
#include <time.h>
31
#include <stdarg.h>
32
33
static struct App_ {
34
const char * argv0;
35
time_t now;
36
FILE * ostr;
37
} App = {
38
0, 0, 0
39
};
40
41
static void err(const char *zFmt, ...){
42
va_list vargs;
43
va_start(vargs, zFmt);
44
fputs("ERROR: ",stderr);
45
vfprintf(stderr, zFmt, vargs);
46
fputc('\n', stderr);
47
va_end(vargs);
48
}
49
50
static void app_usage(int isErr){
51
FILE * const ios = isErr ? stderr : stdout;
52
fprintf(ios, "Usage: %s ?OPTIONS? input-filename...\n\n",
53
App.argv0);
54
fprintf(ios, "Each filename must be one file which is conventionally "
55
"part of a Fossil SCM skin set:\n"
56
" css.txt, header.txt, footer.txt, details.txt, js.txt\n");
57
fprintf(ios, "\nOptions:\n");
58
fprintf(ios, "\n\t-o FILENAME = send output to the given file. "
59
"'-' means stdout (the default).\n");
60
fputc('\n', ios);
61
}
62
63
/*
64
** Reads file zFilename, stores its contents in *zContent, and sets the
65
** length of its contents to *nContent.
66
**
67
** Returns 0 on success. On error, *zContent and *nContent are not
68
** modified and it may emit a message describing the problem.
69
*/
70
int read_file(char const *zFilename, unsigned char ** zContent,
71
int * nContent){
72
long fpos;
73
int rc = 0;
74
unsigned char * zMem = 0;
75
FILE * f = fopen(zFilename, "rb");
76
if(!f){
77
err("Cannot open file %s. Errno=%d", zFilename, errno);
78
return errno;
79
}
80
fseek(f, 0L, SEEK_END);
81
rc = errno;
82
if(rc){
83
err("Cannot seek() file %s. Errno=%d", zFilename, rc);
84
goto end;
85
}
86
fpos = ftell(f);
87
fseek(f, 0L, SEEK_SET);
88
zMem = (unsigned char *)malloc((size_t)fpos + 1);
89
if(!zMem){
90
err("Malloc failed.");
91
rc = ENOMEM;
92
goto end;
93
}
94
zMem[fpos] = 0;
95
if(fpos && (size_t)1 != fread(zMem, (size_t)fpos, 1, f)){
96
rc = EIO;
97
err("Error #%d reading file %s", rc, zFilename);
98
goto end;
99
}
100
end:
101
fclose(f);
102
if(rc){
103
free(zMem);
104
}else{
105
*zContent = zMem;
106
*nContent = fpos;
107
}
108
return rc;
109
}
110
111
/*
112
** Expects zFilename to be one of the conventional skin filename
113
** parts. This routine converts it to config format and emits it to
114
** App.ostr.
115
*/
116
int dispatch_file(char const *zFilename){
117
const char * zKey = 0;
118
int nContent = 0, nContent2 = 0, nOut = 0, nTime = 0, rc = 0;
119
time_t theTime = App.now;
120
unsigned char * zContent = 0;
121
unsigned char * z = 0;
122
if(strstr(zFilename, "css.txt")){
123
zKey = "css";
124
}else if(strstr(zFilename, "header.txt")){
125
zKey = "header";
126
}else if(strstr(zFilename, "footer.txt")){
127
zKey = "footer";
128
}else if(strstr(zFilename, "details.txt")){
129
zKey = "details";
130
}else if(strstr(zFilename, "js.txt")){
131
zKey = "js";
132
}else {
133
err("Cannot determine skin part from filename: %s", zFilename);
134
return 1;
135
}
136
rc = read_file(zFilename, &zContent, &nContent);
137
if(rc) return rc;
138
for( z = zContent; z < zContent + nContent; ++z ){
139
/* Count file content length with ' characters doubled */
140
nContent2 += ('\'' == *z) ? 2 : 1;
141
}
142
while(theTime > 0){/* # of digits in time */
143
++nTime;
144
theTime /= 10;
145
}
146
fprintf(App.ostr, "config /config %d\n",
147
(int)(nTime + 12/*"value"+spaces+quotes*/
148
+ (int)strlen(zKey) + nContent2));
149
fprintf(App.ostr, "%d '%s' value '", (int)App.now, zKey);
150
for( z = zContent; z < zContent + nContent; ++z ){
151
/* Emit file content with ' characters doubled */
152
if('\'' == (char)*z){
153
fputc('\'', App.ostr);
154
}
155
fputc((char)*z, App.ostr);
156
}
157
free(zContent);
158
fprintf(App.ostr, "'\n");
159
return 0;
160
}
161
162
int main(int argc, char const * const * argv){
163
int rc = 0, i ;
164
App.argv0 = argv[0];
165
App.ostr = stdout;
166
if(argc<2){
167
app_usage(1);
168
rc = 1;
169
goto end;
170
}
171
App.now = time(0);
172
for( i = 1; i < argc; ++i ){
173
const char * zArg = argv[i];
174
if(0==strcmp(zArg,"help") ||
175
0==strcmp(zArg,"--help") ||
176
0==strcmp(zArg,"-?")){
177
app_usage(0);
178
rc = 0;
179
break;
180
}else if(0==strcmp(zArg,"-o")){
181
/* -o OUTFILE (- == stdout) */
182
++i;
183
if(i==argc){
184
err("Missing filename for -o flag");
185
rc = 1;
186
break;
187
}else{
188
const char *zOut = argv[i];
189
if(App.ostr != stdout){
190
err("Cannot specify -o more than once.");
191
rc = 1;
192
break;
193
}
194
if(0!=strcmp("-",zOut)){
195
FILE * o = fopen(zOut, "wb");
196
if(!o){
197
err("Could not open file %s for writing. Errno=%d",
198
zOut, errno);
199
rc = errno;
200
break;
201
}
202
App.ostr = o;
203
}
204
}
205
}else if('-' == zArg[0]){
206
err("Unhandled argument: %s", zArg);
207
rc = 1;
208
break;
209
}else{
210
rc = dispatch_file(zArg);
211
if(rc) break;
212
}
213
}
214
end:
215
if(App.ostr != stdout){
216
fclose(App.ostr);
217
}
218
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
219
}
220

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button