1 /* Generate .po file from doc-string file.
3 Scan specified doc-string file, creating .po format messages for processing
4 with msgfmt. The results go to standard output or to a file specified
5 with -a or -o (-a to append, -o to start from nothing).
7 Kludge to make up for shortcoming in make-docfile and Snarf-documentation:
8 If arg before input filename is -p, we are scanning an add-on
9 package, which requires slightly different processing.
16 #define EXIT_SUCCESS 0
17 #define EXIT_FAILURE 1
20 /* #define BUFSIZE 8192 */
21 /* #define BUFSIZE 16384 */
23 #define NEWSTRING 31 /* Character signalling start of new doc string */
25 #define ENDSTRING "\"\n"
26 #define LINEBEGIN " \""
27 #define LINEBREAK ENDSTRING LINEBEGIN
29 /* some brain-dead headers define this ... */
32 enum boolean { FALSE, TRUE };
34 /***********************/
35 /* buffer pseudo-class */
36 /***********************/
38 typedef struct _buffer {
39 size_t index; /* current position in buf[] */
40 size_t size; /* size of buf */
44 #define BUF_NULL {0, 0, NULL}
46 int buf_init(buffer_struct * buffer, size_t size);
47 void buf_free(buffer_struct * buffer);
48 void buf_clear(buffer_struct * buffer);
49 int buf_putc(buffer_struct * buffer, int c);
50 int buf_print(buffer_struct * buffer, const char *s);
52 /********************/
53 /* global variables */
54 /********************/
58 buffer_struct buf = BUF_NULL;
60 void scan_file(enum boolean package);
61 void initialize(void);
62 void clean_exit(int status);
63 void buf_putc_safe(int c);
64 void buf_print_safe(const char *s);
65 void terminate_string(void);
67 main(int argc, char *argv[])
70 enum boolean package = FALSE; /* TRUE if scanning add-on package */
76 /* If first two args are -o FILE, output to FILE. */
78 if (argc > i + 1 && strcmp(argv[i], "-o") == 0) {
79 outfile = fopen(argv[++i], "w");
82 /* ...Or if args are -a FILE, append to FILE. */
83 if (argc > i + 1 && strcmp(argv[i], "-a") == 0) {
84 outfile = fopen(argv[++i], "a");
88 fprintf(stderr, "Unable to open output file %s\n", argv[--i]);
92 if (argc > i && !strcmp(argv[i], "-p")) {
97 infile = fopen(argv[i], "r");
99 fprintf(stderr, "Unable to open input file %s\n", argv[i]);
104 clean_exit(EXIT_SUCCESS);
107 void scan_file(enum boolean package)
109 register int c; /* Character read in */
111 fprintf(outfile, "###############\n");
112 fprintf(outfile, "# DOC strings #\n");
113 fprintf(outfile, "###############\n");
115 while (c = getc(infile), !feof(infile)) {
116 if (c == NEWSTRING) {
117 /* If a string was being processed, terminate it. */
121 /* Skip function or variable name. */
126 /* Begin a new string. */
127 fprintf(outfile, "msgid \"");
128 buf_print_safe("msgstr \"");
132 /* Peek at next character. */
136 /* For add-on (i.e., non-preloaded) documentation, ignore the last
137 carriage return of a string. */
138 if (!(package && c == NEWSTRING)) {
139 fprintf(outfile, LINEEND);
140 buf_print_safe(LINEEND);
143 /* If not end of string, continue it on the next line. */
144 if (c != NEWSTRING) {
145 fprintf(outfile, LINEBREAK);
146 buf_print_safe(LINEBREAK);
150 /* If character is \ or ", precede it by a backslash. */
151 if (c == '\\' || c == '\"') {
163 /* initialize sets up the global variables.
165 void initialize(void)
167 if (buf_init(&buf, BUFSIZE) != 0)
168 clean_exit(EXIT_FAILURE);
171 /* clean_exit returns any resources and terminates the program.
172 An error message is printed if status is EXIT_FAILURE.
174 void clean_exit(int status)
183 if (status == EXIT_FAILURE)
184 fprintf(stderr, "make-po abnormally terminated\n");
188 /* buf_putc_safe writes the character c on the global buffer buf,
189 checking to make sure that the operation was successful.
191 void buf_putc_safe(int c)
195 status = buf_putc(&buf, c);
197 clean_exit(EXIT_FAILURE);
200 /* buf_putc_safe writes the string s on the global buffer buf,
201 checking to make sure that the operation was successful.
203 void buf_print_safe(const char *s)
207 status = buf_print(&buf, s);
209 clean_exit(EXIT_FAILURE);
212 /* terminate_string terminates the current doc string and outputs the buffer.
214 void terminate_string(void)
216 fprintf(outfile, ENDSTRING);
218 /* Make the "translation" different from the original string. */
219 buf_print_safe("_X");
221 buf_print_safe(ENDSTRING);
222 fprintf(outfile, "%s", buf.buf);
226 /*********************************/
227 /* buffer pseudo-class functions */
228 /*********************************/
230 /* buf_init initializes a buffer to the specified size.
231 It returns non-zero if the attempt fails.
233 int buf_init(buffer_struct * buffer, size_t size)
235 buffer->buf = malloc(size);
236 if (buffer->buf == NULL)
244 /* buf_free releases the memory allocated for the buffer.
246 void buf_free(buffer_struct * buffer)
252 /* buf_clear resets a buffer to an empty string.
254 void buf_clear(buffer_struct * buffer)
257 buffer->buf[0] = '\0';
260 /* buf_putc writes the character c on the buffer.
261 It returns the character written, or EOF for error.
263 int buf_putc(buffer_struct * buffer, int c)
265 if (buffer->index >= buffer->size)
268 buffer->buf[buffer->index++] = c;
272 /* buf_print writes the string s on the buffer.
273 It returns the number of characters written, or negative if an error occurred.
275 int buf_print(buffer_struct * buffer, const char *s)
277 register int len, sz, msz = buffer->size - buffer->index;
283 sz = snprintf(&(buffer->buf[buffer->index]), msz, "%s", s);
284 assert(sz>=0 && sz<msz);
285 buffer->index += len;