70
+ − 1 /* Generate .po file from doc-string file.
+ − 2
+ − 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).
+ − 6
+ − 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.
+ − 10 */
+ − 11
+ − 12 #include <stdio.h>
+ − 13 #include <stdlib.h>
+ − 14
+ − 15 #ifndef EXIT_SUCCESS
+ − 16 #define EXIT_SUCCESS 0
+ − 17 #define EXIT_FAILURE 1
+ − 18 #endif
+ − 19
+ − 20 /* #define BUFSIZE 8192 */
444
+ − 21 /* #define BUFSIZE 16384 */
+ − 22 #define BUFSIZE 32768
70
+ − 23 #define NEWSTRING 31 /* Character signalling start of new doc string */
+ − 24 #define LINEEND "\\n"
+ − 25 #define ENDSTRING "\"\n"
+ − 26 #define LINEBEGIN " \""
+ − 27 #define LINEBREAK ENDSTRING LINEBEGIN
+ − 28
+ − 29 /* some brain-dead headers define this ... */
+ − 30 #undef FALSE
+ − 31 #undef TRUE
+ − 32 enum boolean { FALSE, TRUE };
+ − 33
+ − 34
+ − 35 /***********************/
+ − 36 /* buffer pseudo-class */
+ − 37 /***********************/
+ − 38
+ − 39 typedef struct _buffer
+ − 40 {
+ − 41 size_t index; /* current position in buf[] */
+ − 42 size_t size; /* size of buf */
+ − 43 char *buf;
+ − 44 } buffer_struct;
+ − 45
+ − 46 #define BUF_NULL {0, 0, NULL}
+ − 47
+ − 48 int buf_init (buffer_struct *buffer, size_t size);
+ − 49 void buf_free (buffer_struct *buffer);
+ − 50 void buf_clear (buffer_struct *buffer);
+ − 51 int buf_putc (buffer_struct *buffer, int c);
+ − 52 int buf_print (buffer_struct *buffer, const char *s);
+ − 53
+ − 54
+ − 55 /********************/
+ − 56 /* global variables */
+ − 57 /********************/
+ − 58
+ − 59 FILE *infile = NULL;
+ − 60 FILE *outfile = NULL;
+ − 61 buffer_struct buf = BUF_NULL;
+ − 62
+ − 63
+ − 64 void scan_file (enum boolean package);
+ − 65 void initialize (void);
+ − 66 void clean_exit (int status);
+ − 67 void buf_putc_safe (int c);
+ − 68 void buf_print_safe (const char *s);
+ − 69 void terminate_string (void);
+ − 70
+ − 71 main (int argc, char *argv[])
+ − 72 {
+ − 73 register int i;
+ − 74 enum boolean package = FALSE; /* TRUE if scanning add-on package */
+ − 75
+ − 76 initialize ();
+ − 77
+ − 78 outfile = stdout;
+ − 79
+ − 80 /* If first two args are -o FILE, output to FILE. */
+ − 81 i = 1;
+ − 82 if (argc > i + 1 && strcmp (argv[i], "-o") == 0) {
+ − 83 outfile = fopen (argv[++i], "w");
+ − 84 ++i;
+ − 85 }
+ − 86 /* ...Or if args are -a FILE, append to FILE. */
+ − 87 if (argc > i + 1 && strcmp (argv[i], "-a") == 0) {
+ − 88 outfile = fopen (argv[++i], "a");
+ − 89 ++i;
+ − 90 }
+ − 91 if (!outfile) {
+ − 92 fprintf (stderr, "Unable to open output file %s\n", argv[--i]);
+ − 93 return 1;
+ − 94 }
+ − 95
+ − 96 if (argc > i && !strcmp (argv[i], "-p")) {
+ − 97 package = TRUE;
+ − 98 ++i;
+ − 99 }
+ − 100
+ − 101 infile = fopen (argv[i], "r");
+ − 102 if (!infile) {
+ − 103 fprintf (stderr, "Unable to open input file %s\n", argv[i]);
+ − 104 return 1;
+ − 105 }
+ − 106
+ − 107 scan_file (package);
+ − 108 clean_exit (EXIT_SUCCESS);
+ − 109 }
+ − 110
+ − 111
+ − 112 void scan_file (enum boolean package)
+ − 113 {
+ − 114 register int c; /* Character read in */
+ − 115
+ − 116 fprintf (outfile, "###############\n");
+ − 117 fprintf (outfile, "# DOC strings #\n");
+ − 118 fprintf (outfile, "###############\n");
+ − 119
+ − 120 while (c = getc (infile), !feof (infile)) {
+ − 121 if (c == NEWSTRING) {
+ − 122 /* If a string was being processed, terminate it. */
+ − 123 if (buf.index > 0)
+ − 124 terminate_string ();
+ − 125
+ − 126 /* Skip function or variable name. */
+ − 127 while (c != '\n')
+ − 128 c = getc (infile);
+ − 129 c = getc (infile);
+ − 130
+ − 131 /* Begin a new string. */
+ − 132 fprintf (outfile, "msgid \"");
+ − 133 buf_print_safe ("msgstr \"");
+ − 134 }
+ − 135
+ − 136 if (c == '\n') {
+ − 137 /* Peek at next character. */
+ − 138 c = getc (infile);
+ − 139 ungetc (c, infile);
+ − 140
+ − 141 /* For add-on (i.e., non-preloaded) documentation, ignore the last
+ − 142 carriage return of a string. */
+ − 143 if (!(package && c == NEWSTRING)) {
+ − 144 fprintf (outfile, LINEEND);
+ − 145 buf_print_safe (LINEEND);
+ − 146 }
+ − 147
+ − 148 /* If not end of string, continue it on the next line. */
+ − 149 if (c != NEWSTRING) {
+ − 150 fprintf (outfile, LINEBREAK);
+ − 151 buf_print_safe (LINEBREAK);
+ − 152 }
+ − 153 }
+ − 154 else {
+ − 155
+ − 156 /* If character is \ or ", precede it by a backslash. */
+ − 157 if (c == '\\' || c == '\"') {
+ − 158 putc ('\\', outfile);
+ − 159 buf_putc_safe ('\\');
+ − 160 }
+ − 161
+ − 162 putc (c, outfile);
+ − 163 buf_putc_safe (c);
+ − 164 }
+ − 165 }
+ − 166 terminate_string ();
+ − 167 }
+ − 168
+ − 169
+ − 170 /* initialize sets up the global variables.
+ − 171 */
+ − 172 void initialize (void)
+ − 173 {
+ − 174 if (buf_init (&buf, BUFSIZE) != 0)
+ − 175 clean_exit (EXIT_FAILURE);
+ − 176 }
+ − 177
+ − 178
+ − 179 /* clean_exit returns any resources and terminates the program.
+ − 180 An error message is printed if status is EXIT_FAILURE.
+ − 181 */
+ − 182 void clean_exit (int status)
+ − 183 {
+ − 184 if (buf.size > 0)
+ − 185 buf_free (&buf);
+ − 186 if (outfile)
+ − 187 fclose (outfile);
+ − 188 if (infile)
+ − 189 fclose (infile);
+ − 190
+ − 191 if (status == EXIT_FAILURE)
+ − 192 fprintf (stderr, "make-po abnormally terminated\n");
+ − 193 exit (status);
+ − 194 }
+ − 195
+ − 196
+ − 197 /* buf_putc_safe writes the character c on the global buffer buf,
+ − 198 checking to make sure that the operation was successful.
+ − 199 */
+ − 200 void buf_putc_safe (int c)
+ − 201 {
+ − 202 register int status;
+ − 203
+ − 204 status = buf_putc (&buf, c);
+ − 205 if (status == EOF)
+ − 206 clean_exit (EXIT_FAILURE);
+ − 207 }
+ − 208
+ − 209
+ − 210 /* buf_putc_safe writes the string s on the global buffer buf,
+ − 211 checking to make sure that the operation was successful.
+ − 212 */
+ − 213 void buf_print_safe (const char *s)
+ − 214 {
+ − 215 register int status;
+ − 216
+ − 217 status = buf_print (&buf, s);
+ − 218 if (status < 0)
+ − 219 clean_exit (EXIT_FAILURE);
+ − 220 }
+ − 221
+ − 222
+ − 223 /* terminate_string terminates the current doc string and outputs the buffer.
+ − 224 */
+ − 225 void terminate_string (void)
+ − 226 {
+ − 227 fprintf (outfile, ENDSTRING);
+ − 228
+ − 229 /* Make the "translation" different from the original string. */
+ − 230 buf_print_safe ("_X");
+ − 231
+ − 232 buf_print_safe (ENDSTRING);
+ − 233 fprintf (outfile, "%s", buf.buf);
+ − 234 buf_clear (&buf);
+ − 235 }
+ − 236
+ − 237
+ − 238 /*********************************/
+ − 239 /* buffer pseudo-class functions */
+ − 240 /*********************************/
+ − 241
+ − 242 /* buf_init initializes a buffer to the specified size.
+ − 243 It returns non-zero if the attempt fails.
+ − 244 */
+ − 245 int buf_init (buffer_struct *buffer, size_t size)
+ − 246 {
+ − 247 buffer->buf = malloc (size);
+ − 248 if (buffer->buf == NULL)
+ − 249 return 1;
+ − 250
+ − 251 buffer->size = size;
+ − 252 buf_clear (buffer);
+ − 253 return 0;
+ − 254 }
+ − 255
+ − 256
+ − 257 /* buf_free releases the memory allocated for the buffer.
+ − 258 */
+ − 259 void buf_free (buffer_struct *buffer)
+ − 260 {
+ − 261 free (buffer->buf);
+ − 262 buffer->size = 0;
+ − 263 }
+ − 264
+ − 265
+ − 266 /* buf_clear resets a buffer to an empty string.
+ − 267 */
+ − 268 void buf_clear (buffer_struct *buffer)
+ − 269 {
+ − 270 buffer->index = 0;
+ − 271 buffer->buf[0] = '\0';
+ − 272 }
+ − 273
+ − 274
+ − 275 /* buf_putc writes the character c on the buffer.
+ − 276 It returns the character written, or EOF for error.
+ − 277 */
+ − 278 int buf_putc (buffer_struct *buffer, int c)
+ − 279 {
+ − 280 if (buffer->index >= buffer->size)
+ − 281 return EOF;
+ − 282
+ − 283 buffer->buf[buffer->index++] = c;
+ − 284 return c;
+ − 285 }
+ − 286
+ − 287
+ − 288 /* buf_print writes the string s on the buffer.
+ − 289 It returns the number of characters written, or negative if an error occurred.
+ − 290 */
+ − 291 int buf_print (buffer_struct *buffer, const char *s)
+ − 292 {
+ − 293 register int len;
+ − 294
+ − 295 len = strlen (s);
+ − 296 if (buffer->index + len >= buffer->size)
+ − 297 return -1;
+ − 298
+ − 299 sprintf (&(buffer->buf[buffer->index]), s);
+ − 300 buffer->index += len;
+ − 301 return len;
+ − 302 }