~ubuntu-branches/ubuntu/karmic/pilot-link/karmic

« back to all changes in this revision

Viewing changes to src/pilot-datebook/pilot-datebook-longtxt.c

  • Committer: Bazaar Package Importer
  • Author(s): Ludovic Rousseau
  • Date: 2006-09-22 11:51:36 UTC
  • mfrom: (3.1.8 edgy)
  • Revision ID: james.westby@ubuntu.com-20060922115136-qqmy17bx8j5x0y72
Tags: 0.12.1-5
* urgency medium since libpisock-dev was not usable to build any package
* libpisock-dev now depends on libusb-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Pilot Datebook processing utility
3
 
 *
4
 
 * (c) 2000, Matthias Hessler <pilot-datebook@mhessler.de>
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify it
7
 
 * under the terms of the GNU General Public License as published by the
8
 
 * Free Software Foundation; either version 2 of the License, or (at your
9
 
 * option) any later version.
10
 
 *
11
 
 * This program is distributed in the hope that it will be useful, but
12
 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
14
 
 * Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License along
17
 
 * with this program; if not, write to the Free Software Foundation, Inc.,
18
 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
 
 *
20
 
 */
21
 
 
22
 
#include <string.h>
23
 
#include "pilot-datebook-longtxt.h"
24
 
 
25
 
/* longtxt is a lossless file format, and designed to be human-readable.
26
 
 * Since it may change over time, it is not guaranteed to read in files
27
 
 * written in earlier versions of longtxt.
28
 
 *
29
 
 * It is actually the best output format, as it will capture even more data
30
 
 * than can be stored in pdb files (fields index, misc_flag).
31
 
 * Therefore best results for reading are achieved when reading via hotsync
32
 
 * and writing longtxt.
33
 
 */
34
 
 
35
 
 
36
 
/* Read/write header format */
37
 
/* Due to usage of scanf, can not suround strings with any delimiters
38
 
 * other than white space or end of line
39
 
 */
40
 
const char LONGTXT_HEADER_NAME_FORMAT[] = "name=%s\n";
41
 
const char LONGTXT_HEADER_FLAGS_FORMAT[] = "flags=0x%x%s%s%s%s%s%s%s\n";
42
 
const char LONGTXT_HEADER_MISC_FLAGS_FORMAT[] = "misc_flags=0x%x\n";
43
 
const char LONGTXT_HEADER_TYPE_FORMAT[] = "type=%s\n";
44
 
const char LONGTXT_HEADER_CREATOR_FORMAT[] = "creator=%s\n";
45
 
const char LONGTXT_HEADER_VERSION_FORMAT[] = "version=%d\n";
46
 
const char LONGTXT_HEADER_MODIFICATION_FORMAT[] = "modification_number=%ld\n";
47
 
const char LONGTXT_HEADER_CREATE_TIME_FORMAT[] = "creation_time=%s%s%s%s\n";
48
 
const char LONGTXT_HEADER_MODIFY_TIME_FORMAT[] = "modified_time=%s%s%s%s\n";
49
 
const char LONGTXT_HEADER_BACKUP_TIME_FORMAT[] = "backup_time=%s%s%s%s\n";
50
 
const char LONGTXT_HEADER_INDEX_FORMAT[] = "index=%u\n";
51
 
const char LONGTXT_HEADER_CATEGORY_HEADER1_FORMAT[] = "Categories\n";
52
 
const char LONGTXT_HEADER_CATEGORY_HEADER2_FORMAT[] = "#\tID\tRenamed\tName\n";
53
 
const char LONGTXT_HEADER_CATEGORY_ROW_FORMAT[] = "%d\t%u\t%s\t%s%s\n";
54
 
const char LONGTXT_HEADER_RENAMED_YES[] = "Yes";
55
 
const char LONGTXT_HEADER_RENAMED_NO[] = "No";
56
 
const char LONGTXT_HEADER_RENAMED_UNUSED[] = "(unused)";
57
 
 
58
 
const char LONGTXT_HEADER_LAST_UNIQUE_ID_FORMAT[] = "Last unique ID=%u\n";
59
 
const char LONGTXT_HEADER_START_OF_WEEK_FORMAT[] = "Start of week: %d\n";
60
 
const char LONGTXT_HEADER_NO_APP_INFO[] = "No application info found.\n";
61
 
const char LONGTXT_HEADER_NO_SORT_INFO[] = "No sort info found.\n";
62
 
 
63
 
 
64
 
/* Read/write row format */
65
 
/* Due to more manual processing, data fields are surrounded by
66
 
 * greater/less than signs, like this: <data_field>
67
 
 */
68
 
const char LONGTXT_ROW_UNTIMED1_FORMAT[] = "UNTIMED_EVENT <";
69
 
const char LONGTXT_ROW_UNTIMED2_FORMAT[] = "> on <";
70
 
const char LONGTXT_ROW_UNTIMED3_FORMAT[] = ">:";
71
 
const char LONGTXT_ROW_APPOINTMENT1_FORMAT[] = "APPOINTMENT <";
72
 
const char LONGTXT_ROW_APPOINTMENT2_FORMAT[] = "> from <";
73
 
const char LONGTXT_ROW_APPOINTMENT3_FORMAT[] = "> to <";
74
 
const char LONGTXT_ROW_APPOINTMENT4_FORMAT[] = ">:";
75
 
const char LONGTXT_ROW_ATTRIBUTES_FORMAT[] = "attributes=0x%x%s%s%s%s%s\n";
76
 
const char LONGTXT_ROW_CATEGORY_FORMAT[] = "category=%d (%s)\n";
77
 
 
78
 
const char LONGTXT_ROW_REPEAT1_FORMAT[] = "REPEAT from <";
79
 
const char LONGTXT_ROW_REPEAT2_FORMAT[] = "> until <";
80
 
const char LONGTXT_ROW_REPEAT3_FORMAT[] = ">: <";
81
 
const char LONGTXT_ROW_REPEAT4_FORMAT[] = ">";
82
 
const char LONGTXT_ROW_REPEAT_FOREVER_CONST[] = "forever";
83
 
const char LONGTXT_ROW_REPEAT_DAILY_CONST[] = "daily";
84
 
const char LONGTXT_ROW_REPEAT_WEEKLY_CONST[] = "weekly";
85
 
const char LONGTXT_ROW_REPEAT_MONTHLY_LAST_WEEK_CONST[] = "monthly/last_weekday";
86
 
const char LONGTXT_ROW_REPEAT_MONTHLY_WEEKDAY_CONST[] = "monthly/weekday";
87
 
const char LONGTXT_ROW_REPEAT_MONTHLY_CONST[] = "monthly";
88
 
const char LONGTXT_ROW_REPEAT_YEARLY_CONST[] = "yearly";
89
 
const char LONGTXT_ROW_REPEAT_UNKNOWN_CONST[] = "unknown";
90
 
 
91
 
const char LONGTXT_ROW_REPEAT_WEEKLY_FORMAT[] = "%s%s%s%s%s%s%s";
92
 
const char LONGTXT_ROW_REPEAT_MONTHLY_FORMAT[] = "%d";
93
 
const char LONGTXT_ROW_REPEAT_MONTHLY_LAST_WEEK_FORMAT[] = "%s %d";
94
 
const char LONGTXT_ROW_REPEAT_MONTHLY_WEEKDAY_FORMAT[] = "%s ge %d";
95
 
 
96
 
const char LONGTXT_ROW_REPEAT_YEARLY_FORMAT[] = "%s %d";
97
 
const char LONGTXT_ROW_REPEAT_PARAM1_FORMAT[] = " on <";
98
 
const char LONGTXT_ROW_REPEAT_PARAM2_FORMAT[] = ">";
99
 
const char LONGTXT_ROW_REPEAT_WEEKSTART1_FORMAT[] = " week starts <";
100
 
const char LONGTXT_ROW_REPEAT_WEEKSTART2_FORMAT[] = ">";
101
 
 
102
 
const char LONGTXT_ROW_REPEAT_FREQUENCY1_FORMAT[] = " every <";
103
 
const char LONGTXT_ROW_REPEAT_FREQUENCY2_FORMAT[] = "> times";
104
 
 
105
 
const char LONGTXT_ROW_REPEAT_OMIT1_FORMAT[] = "  OMIT: <";
106
 
const char LONGTXT_ROW_REPEAT_OMIT2_FORMAT[] = "> <";
107
 
const char LONGTXT_ROW_REPEAT_OMIT3_FORMAT[] = ">";
108
 
 
109
 
const char LONGTXT_ROW_ALARM1_FORMAT[] = "ALARM <";
110
 
const char LONGTXT_ROW_ALARM2_FORMAT[] = "%d %s before>";
111
 
const char LONGTXT_ROW_ALARM_MIN_CONST[] = "min";
112
 
const char LONGTXT_ROW_ALARM_HOURS_CONST[] = "hours";
113
 
const char LONGTXT_ROW_ALARM_DAYS_CONST[] = "days";
114
 
const char LONGTXT_ROW_ALARM_UNKNOWN_CONST[] = "unknown_unit";
115
 
 
116
 
const char LONGTXT_ROW_NOTE_FORMAT[] = "NOTE:\n";
117
 
 
118
 
 
119
 
 
120
 
/* Public functions */
121
 
 
122
 
/* For init */
123
 
 
124
 
/* Initialize read data structure */
125
 
int
126
 
longtxt_init_read (struct longtxt_file_data * in_file)
127
 
{
128
 
 
129
 
  /* Debug */
130
 
  debug_message("Entering longtxt_init_read\n");
131
 
 
132
 
  /* Init own data structure */
133
 
  in_file->filename = NULL;
134
 
  in_file->file = NULL;
135
 
  in_file->file_is_open = FALSE;
136
 
  in_file->line_buffer = NULL;
137
 
  in_file->line_no = 0;
138
 
  in_file->num_recs = 0;
139
 
  in_file->next_rec = 0;
140
 
  in_file->lines_read = 0;
141
 
  in_file->lines_written = 0;
142
 
  in_file->records_read = 0;
143
 
  in_file->records_written = 0;
144
 
 
145
 
  /* Debug */
146
 
  debug_message("Leaving longtxt_init_read\n");
147
 
 
148
 
  return TRUE;
149
 
}
150
 
 
151
 
 
152
 
/* Initialize write data structure */
153
 
int
154
 
longtxt_init_write (struct longtxt_file_data * out_file)
155
 
{
156
 
 
157
 
  /* Debug */
158
 
  debug_message("Entering longtxt_init_write\n");
159
 
 
160
 
  /* Init own data structure */
161
 
  out_file->filename = NULL;
162
 
  out_file->file = NULL;
163
 
  out_file->file_is_open = FALSE;
164
 
  out_file->line_buffer = NULL;
165
 
  out_file->line_no = 0;
166
 
  out_file->num_recs = 0;
167
 
  out_file->next_rec = 0;
168
 
  out_file->lines_read = 0;
169
 
  out_file->lines_written = 0;
170
 
  out_file->records_read = 0;
171
 
  out_file->records_written = 0;
172
 
 
173
 
  /* Debug */
174
 
  debug_message("Leaving longtxt_init_write\n");
175
 
 
176
 
  return TRUE;
177
 
}
178
 
 
179
 
 
180
 
/* Destroy read data structure */
181
 
void
182
 
longtxt_exit_read (struct longtxt_file_data * in_file)
183
 
{
184
 
 
185
 
  /* Debug */
186
 
  debug_message("Entering longtxt_exit_read\n");
187
 
 
188
 
  /* Free memory */
189
 
  if (in_file->filename)
190
 
    free (in_file->filename);
191
 
 
192
 
  /* Debug */
193
 
  debug_message("Leaving longtxt_exit_read\n");
194
 
}
195
 
 
196
 
 
197
 
/* Destroy write data structure */
198
 
void
199
 
longtxt_exit_write (struct longtxt_file_data * out_file)
200
 
{
201
 
 
202
 
  /* Debug */
203
 
  debug_message("Entering longtxt_exit_write\n");
204
 
 
205
 
  /* Free memory */
206
 
  if (out_file->filename)
207
 
    free (out_file->filename);
208
 
 
209
 
  /* Debug */
210
 
  debug_message("Leaving longtxt_exit_write\n");
211
 
}
212
 
 
213
 
 
214
 
/* Set read command line option */
215
 
int
216
 
longtxt_set_read_option (struct longtxt_file_data * in_file, char opt, char * opt_arg)
217
 
{
218
 
  int rc = FALSE;
219
 
 
220
 
 
221
 
  /* Debug */
222
 
  debug_message("Entering longtxt_set_read_option\n");
223
 
 
224
 
  switch (opt)
225
 
    {
226
 
    case 'f':
227
 
      /* Filename */
228
 
      if (opt_arg != NULL
229
 
          && *opt_arg != '\0') {
230
 
        if (in_file->filename)
231
 
          free (in_file->filename);
232
 
        in_file->filename = strdup(opt_arg);
233
 
        rc = TRUE;
234
 
      }
235
 
      break;
236
 
    default:
237
 
      fprintf(stderr, "Can not process read option <%c> for input file\n",
238
 
              opt);
239
 
    }
240
 
 
241
 
  /* Debug */
242
 
  debug_message("Leaving longtxt_set_read_option\n");
243
 
 
244
 
  return rc;
245
 
}
246
 
 
247
 
 
248
 
/* Set write command line option */
249
 
int
250
 
longtxt_set_write_option (struct longtxt_file_data * out_file, char opt, char * opt_arg)
251
 
{
252
 
  int rc = FALSE;
253
 
 
254
 
 
255
 
  /* Debug */
256
 
  debug_message("Entering longtxt_set_write_option\n");
257
 
 
258
 
  switch (opt)
259
 
    {
260
 
    case 'f':
261
 
      /* Filename */
262
 
      if (opt_arg != NULL
263
 
          && *opt_arg != '\0') {
264
 
        if (out_file->filename)
265
 
          free (out_file->filename);
266
 
        out_file->filename = strdup(opt_arg);
267
 
        rc = TRUE;
268
 
      }
269
 
      break;
270
 
    default:
271
 
      fprintf(stderr, "Can not process write option <%c> for input file\n",
272
 
              opt);
273
 
    }
274
 
 
275
 
  /* Debug */
276
 
  debug_message("Leaving longtxt_set_write_option\n");
277
 
 
278
 
  return rc;
279
 
}
280
 
 
281
 
 
282
 
 
283
 
/* For opening & closing */
284
 
 
285
 
/* Open input data file for reading */
286
 
void
287
 
longtxt_open_read (struct longtxt_file_data * in_file, struct header_data * header)
288
 
{
289
 
 
290
 
  /* Debug */
291
 
  debug_message("Entering longtxt_open_read\n");
292
 
 
293
 
  /* Open file */
294
 
  /* Read from stdin if file name not given */
295
 
  if (!in_file->filename) {
296
 
    /* No open is needed when writing to stdout */
297
 
    in_file->file = stdin;
298
 
  }
299
 
  else {
300
 
    in_file->file = fopen (in_file->filename, "r");
301
 
    if (!in_file->file)
302
 
      error_message("Can not open file <%s> for reading\n",
303
 
                    in_file->filename);
304
 
    in_file->file_is_open = TRUE;
305
 
  }
306
 
 
307
 
  /* Init */
308
 
  in_file->line_buffer = NULL;
309
 
  in_file->line_no = 0;
310
 
  in_file->num_recs = 0;
311
 
  in_file->next_rec = 0;
312
 
 
313
 
  /* Read header data */
314
 
  longtxt_read_header (in_file, header);
315
 
 
316
 
  /* Debug */
317
 
  debug_message("Leaving longtxt_open_read\n");
318
 
}
319
 
 
320
 
 
321
 
/* Open output data file for writing */
322
 
void
323
 
longtxt_open_write (struct longtxt_file_data * out_file, struct header_data * header)
324
 
{
325
 
 
326
 
  /* Debug */
327
 
  debug_message("Entering longtxt_open_write\n");
328
 
 
329
 
  /* Open file */
330
 
  /* Write to stdout if file name not given or "-" */
331
 
  if (!out_file->filename) {
332
 
    /* No open is needed when writing to stdout */
333
 
    out_file->file = stdout;
334
 
  }
335
 
  else {
336
 
    out_file->file = fopen(out_file->filename, "w");
337
 
    if (!out_file->file)
338
 
      error_message("Can not open file <%s> for writing\n",
339
 
                    out_file->filename);
340
 
    out_file->file_is_open = TRUE;
341
 
  }
342
 
 
343
 
  /* Init */
344
 
  out_file->line_buffer = NULL;
345
 
  out_file->line_no = 0;
346
 
  out_file->num_recs = 0;
347
 
  out_file->next_rec = 0;
348
 
 
349
 
  /* Write header */
350
 
  longtxt_write_header (out_file, header);
351
 
 
352
 
  /* Debug */
353
 
  debug_message("Leaving longtxt_open_write\n");
354
 
}
355
 
 
356
 
 
357
 
/* Close input file at end of processing */
358
 
void
359
 
longtxt_close_read (struct longtxt_file_data * in_file, struct header_data * header)
360
 
{
361
 
 
362
 
  /* Debug */
363
 
  debug_message("Entering longtxt_close_read\n");
364
 
 
365
 
  /* Close file */
366
 
  if (in_file->file_is_open == TRUE) {
367
 
    if (fclose (in_file->file))
368
 
      warn_message("Can not close input file\n");
369
 
    in_file->file_is_open = FALSE;
370
 
  }
371
 
 
372
 
  /* Update statistics */
373
 
  in_file->lines_read = in_file->line_no;
374
 
 
375
 
  /* clear data structures */
376
 
  in_file->file = NULL;
377
 
  in_file->line_buffer = NULL;
378
 
  in_file->line_no = 0;
379
 
  in_file->num_recs = 0;
380
 
  in_file->next_rec = 0;
381
 
 
382
 
  /* Debug */
383
 
  debug_message("Leaving longtxt_close_read\n");
384
 
}
385
 
 
386
 
 
387
 
/* Close output file at end of processing */
388
 
void
389
 
longtxt_close_write (struct longtxt_file_data * out_file, struct header_data * header)
390
 
{
391
 
 
392
 
  /* Debug */
393
 
  debug_message("Entering longtxt_close_write\n");
394
 
 
395
 
  /* Close file */
396
 
  if (out_file->file_is_open == TRUE) {
397
 
    if (fclose (out_file->file))
398
 
      warn_message("Can not close output file\n");
399
 
    out_file->file_is_open = FALSE;
400
 
  }
401
 
 
402
 
  /* Update statistics */
403
 
  out_file->lines_written = out_file->line_no;
404
 
 
405
 
  /* Clear data structures */
406
 
  out_file->file = NULL;
407
 
  out_file->line_buffer = NULL;
408
 
  out_file->line_no = 0;
409
 
  out_file->num_recs = 0;
410
 
  out_file->next_rec = 0;
411
 
 
412
 
  /* Debug */
413
 
  debug_message("Leaving longtxt_close_write\n");
414
 
}
415
 
 
416
 
 
417
 
/* Close input file in case of an error */
418
 
void
419
 
longtxt_abort_read (struct longtxt_file_data * in_file)
420
 
{
421
 
 
422
 
  /* Debug */
423
 
  debug_message("Entering longtxt_abort_read\n");
424
 
 
425
 
  /* Close file */
426
 
  if (in_file->file_is_open == TRUE) {
427
 
    if (fclose (in_file->file))
428
 
      warn_message("Can not close input file\n");
429
 
    in_file->file_is_open = FALSE;
430
 
  }
431
 
 
432
 
  /* No special error processing needed */
433
 
 
434
 
  /* Update statistics */
435
 
  in_file->lines_read = in_file->line_no;
436
 
 
437
 
  /* clear data structures */
438
 
  in_file->file = NULL;
439
 
  in_file->line_buffer = NULL;
440
 
  in_file->line_no = 0;
441
 
  in_file->num_recs = 0;
442
 
  in_file->next_rec = 0;
443
 
 
444
 
  /* Debug */
445
 
  debug_message("Leaving longtxt_abort_read\n");
446
 
}
447
 
 
448
 
 
449
 
/* Close output file in case of an error */
450
 
void
451
 
longtxt_abort_write (struct longtxt_file_data * out_file)
452
 
{
453
 
 
454
 
  /* Debug */
455
 
  debug_message("Entering longtxt_abort_write\n");
456
 
 
457
 
  /* Close file */
458
 
  if (out_file->file_is_open == TRUE) {
459
 
    if (fclose (out_file->file))
460
 
      warn_message("Can not close output file\n");
461
 
    out_file->file_is_open = FALSE;
462
 
  }
463
 
 
464
 
  /* Remove incompletely written file */
465
 
  if (out_file->filename) {
466
 
    info_message("Removing incompletely written output file <%s>\n",
467
 
                 out_file->filename);
468
 
    if (out_file->filename)
469
 
      unlink(out_file->filename);
470
 
  }
471
 
 
472
 
  /* Update statistics */
473
 
  out_file->lines_written = out_file->line_no;
474
 
 
475
 
  /* Clear data structures */
476
 
  out_file->file = NULL;
477
 
  out_file->line_buffer = NULL;
478
 
  out_file->line_no = 0;
479
 
  out_file->num_recs = 0;
480
 
  out_file->next_rec = 0;
481
 
 
482
 
  /* Debug */
483
 
  debug_message("Leaving longtxt_abort_write\n");
484
 
}
485
 
 
486
 
 
487
 
 
488
 
/* For reading */
489
 
 
490
 
/* Identify end of file */
491
 
int
492
 
longtxt_read_eof (struct longtxt_file_data * in_file)
493
 
{
494
 
 
495
 
  /* Debug */
496
 
  debug_message("Entering & Leaving longtxt_read_eof\n");
497
 
 
498
 
  return feof(in_file->file);
499
 
}
500
 
 
501
 
 
502
 
/* read routine for appointment in current record */
503
 
void
504
 
longtxt_read_row (struct longtxt_file_data * in_file, struct row_data * row)
505
 
{
506
 
  int len = 0;
507
 
  int i = 0;
508
 
  int j = 0;
509
 
 
510
 
  const char * p1 = NULL;
511
 
  char * b1 = NULL;
512
 
  char * b2 = NULL;
513
 
 
514
 
  int num_read = 0;
515
 
  int mday = 0;
516
 
  int empty_lines = 0;
517
 
 
518
 
  int repeat_last_week = 0;
519
 
  char repeatparam[0xffff];
520
 
 
521
 
  char date_buffer[50];
522
 
 
523
 
  char buffer[0xffff];
524
 
  char buffer1[0xffff];
525
 
  char buffer2[0xffff];
526
 
  char buffer3[0xffff];
527
 
  char buffer4[0xffff];
528
 
  char buffer5[0xffff];
529
 
 
530
 
  time_t t;
531
 
  struct tm tm;
532
 
  struct Appointment a;
533
 
  int attributes = 0;
534
 
  int category = 0;
535
 
  unsigned long uid = 0;
536
 
  int record_num = 0;
537
 
 
538
 
 
539
 
 
540
 
  /* Debug */
541
 
  debug_message("Entering longtxt_read_row\n");
542
 
 
543
 
  /* Ideally, this should be reprogrammed to a real parser (maybe using
544
 
   * yacc or so). A parser would be much faster and safer.
545
 
   * Unfortunately, I don't know how to do that, so I had
546
 
   * to sweat through this hell here.
547
 
   * If someone else knows how to do it better...
548
 
   */
549
 
 
550
 
 
551
 
  /* Init data structures */
552
 
  memset(&a, 0, sizeof(a));
553
 
  memset(&tm, 0, sizeof(tm));
554
 
 
555
 
 
556
 
  /* Read record */
557
 
 
558
 
  /* Skip empty lines */
559
 
  longtxt_read_line(buffer, sizeof(buffer), in_file);
560
 
  while (buffer[0] == '\n') {
561
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
562
 
  }
563
 
  if (feof(in_file->file))
564
 
    error_message("Read unexpected end of input file at line %d\n\n",
565
 
                  in_file->line_no);
566
 
 
567
 
  /* Now parse; per default assume that reading will fail */
568
 
  setRowIsValid(row, FALSE);
569
 
  do {
570
 
    /* Now expect UNTIMED_EVENT or APPOINTMENT */
571
 
    b1 = buffer;
572
 
    p1 = LONGTXT_ROW_UNTIMED1_FORMAT;
573
 
    len = sizeof(LONGTXT_ROW_UNTIMED1_FORMAT) -1;
574
 
    if(!strncmp(b1, p1, len)) {
575
 
      b1 += len;
576
 
 
577
 
      /* Found UNTIMED_EVENT */
578
 
      a.event = 1;
579
 
 
580
 
      /* Read UID */
581
 
      uid = strtoul(b1, &b2, 0);
582
 
      b1 = b2;
583
 
 
584
 
      /* Find event date */
585
 
      p1 = LONGTXT_ROW_UNTIMED2_FORMAT;
586
 
      len = sizeof(LONGTXT_ROW_UNTIMED2_FORMAT) -1;
587
 
      if(strncmp(b1, p1, len)) {
588
 
        warn_message("Can not find event date from input file line %d\n\n",
589
 
                     in_file->line_no);
590
 
        break;
591
 
      }
592
 
      b1 += len;
593
 
 
594
 
      /* Read event date
595
 
       * (assuming here that the first character of the next text string will
596
 
       * always contain the separator)
597
 
       */
598
 
      b2 = data_index(b1, LONGTXT_ROW_UNTIMED3_FORMAT[0]);
599
 
      len = b2-b1;
600
 
      if (len >= sizeof(date_buffer))
601
 
        error_message("Date_buffer size: Can not parse event date from input file line %d\n\n",
602
 
                      in_file->line_no);
603
 
      strncpy(date_buffer, b1, len);
604
 
      date_buffer[len] = '\0';
605
 
      t = read_iso_date_str1 (date_buffer);
606
 
      if (t == -1) {
607
 
        warn_message("Can not parse start date from input file line %d\n\n",
608
 
                     in_file->line_no);
609
 
        break;
610
 
      }
611
 
      b1 = b2;
612
 
      a.begin = *localtime(&t);
613
 
 
614
 
      /* Find end of line */
615
 
      p1 = LONGTXT_ROW_UNTIMED3_FORMAT;
616
 
      len = sizeof(LONGTXT_ROW_UNTIMED3_FORMAT) -1;
617
 
      if(strncmp(b1, p1, len)) {
618
 
        warn_message("Unexpected end of line reading from input file line %d\n\n",
619
 
                     in_file->line_no);
620
 
        break;
621
 
      }
622
 
      b1+=len;
623
 
    }
624
 
 
625
 
 
626
 
    else {
627
 
      /* Check for Appointment */
628
 
      b1 = buffer;
629
 
      p1 = LONGTXT_ROW_APPOINTMENT1_FORMAT;
630
 
      len = sizeof(LONGTXT_ROW_APPOINTMENT1_FORMAT) -1;
631
 
      if(strncmp(b1, p1, len)) {
632
 
        warn_message("Could not parse input file line %d, expected begin of appointment\n\n",
633
 
                     in_file->line_no);
634
 
        break;
635
 
      }
636
 
      else {
637
 
        b1 += len;
638
 
 
639
 
        /* Found APPOINTMENT */
640
 
        a.event = 0;
641
 
 
642
 
        /* Read UID */
643
 
        uid = strtoul(b1, &b2, 0);
644
 
        b1 = b2;
645
 
 
646
 
        /* Find event start date & time */
647
 
        p1 = LONGTXT_ROW_APPOINTMENT2_FORMAT;
648
 
        len = sizeof(LONGTXT_ROW_APPOINTMENT2_FORMAT) -1;
649
 
        if(strncmp(b1, p1, len)) {
650
 
          warn_message("Can not find event start date & time from input file line %d\n\n",
651
 
                       in_file->line_no);
652
 
          break;
653
 
        }
654
 
        b1 += len;
655
 
 
656
 
        /* Read event start date & time
657
 
         * (assuming here that the first character of the next text string will
658
 
         * always contain the separator)
659
 
         */
660
 
        b2 = data_index(b1, LONGTXT_ROW_APPOINTMENT3_FORMAT[0]);
661
 
        len = b2-b1;
662
 
        if (len >= sizeof(date_buffer))
663
 
          error_message("Date_buffer size: Can not read event start date & time from input file line %d\n\n",
664
 
                        in_file->line_no);
665
 
        strncpy(date_buffer, b1, len);
666
 
        date_buffer[len] = '\0';
667
 
        t = read_iso_time_str1 (date_buffer);
668
 
        if (t == -1) {
669
 
          warn_message("Can not parse event start date & time time from input file line %d\n\n",
670
 
                       in_file->line_no);
671
 
          break;
672
 
        }
673
 
        b1 = b2;
674
 
        a.begin = *localtime(&t);
675
 
 
676
 
 
677
 
        /* Find event end date & time */
678
 
        p1 = LONGTXT_ROW_APPOINTMENT3_FORMAT;
679
 
        len = sizeof(LONGTXT_ROW_APPOINTMENT3_FORMAT) -1;
680
 
        if(strncmp(b1, p1, len)) {
681
 
          warn_message("Can not find event end date & time from input file line %d\n\n",
682
 
                       in_file->line_no);
683
 
          break;
684
 
        }
685
 
        b1 += len;
686
 
 
687
 
        /* Read event end date & time
688
 
         * (assuming here that the first character of the next text string will
689
 
         * always contain the separator)
690
 
         */
691
 
        b2 = data_index(b1, LONGTXT_ROW_APPOINTMENT4_FORMAT[0]);
692
 
        len = b2-b1;
693
 
        if (len >= sizeof(date_buffer))
694
 
          error_message("Date_buffer size: Can not read event end date & time from input file line %d\n\n",
695
 
                        in_file->line_no);
696
 
        strncpy(date_buffer, b1, len);
697
 
        date_buffer[len] = '\0';
698
 
        t = read_iso_time_str1 (date_buffer);
699
 
        if (t == -1) {
700
 
          warn_message("Can not parse event end date & time from input file line %d\n\n",
701
 
                       in_file->line_no);
702
 
          break;
703
 
        }
704
 
        b1 = b2;
705
 
        a.end = *localtime(&t);
706
 
 
707
 
        /* Find end of line */
708
 
        p1 = LONGTXT_ROW_APPOINTMENT4_FORMAT;
709
 
        len = sizeof(LONGTXT_ROW_APPOINTMENT4_FORMAT) -1;
710
 
        if(strncmp(b1, p1, len)) {
711
 
          warn_message("Unexpected end of line reading from input file line %d\n\n",
712
 
                       in_file->line_no);
713
 
          break;
714
 
        }
715
 
        b1+=len;
716
 
      } /* else Appointment */
717
 
 
718
 
    } /* else UNTIMED_EVENT or Appointment */
719
 
    
720
 
    /* Read attributes, if present */
721
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
722
 
    num_read = sscanf (buffer, LONGTXT_ROW_ATTRIBUTES_FORMAT,
723
 
                       &attributes,
724
 
                       buffer1,
725
 
                       buffer2,
726
 
                       buffer3,
727
 
                       buffer4,
728
 
                       buffer5);
729
 
    if (num_read > 0) {
730
 
      /* Get next line, if we successfully processed this line */
731
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
732
 
    }
733
 
    else {
734
 
      /* Could not read attributes? Then assume default */
735
 
      attributes = 0;
736
 
    }
737
 
 
738
 
    /* Read category, if present */
739
 
    num_read = sscanf (buffer, LONGTXT_ROW_CATEGORY_FORMAT,
740
 
                       &category,
741
 
                       buffer1);
742
 
    /* Ignoring buffer1 for now, which contains the category name
743
 
     * plus the closing paranthesis - could rebuild or verify category
744
 
     * index table from encountered category id and name
745
 
     */
746
 
    if (num_read > 0) {
747
 
      /* Get next line, if we successfully processed this line */
748
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
749
 
    }
750
 
    else {
751
 
      /* Could not read category? Then assume default */
752
 
      category = 0;
753
 
    }
754
 
 
755
 
 
756
 
    /* Read description until encountering REPEAT, ALARM, NOTE,
757
 
     * UNTIMED_EVENT, APPOINTMENT, or two empty lines.
758
 
     */
759
 
    buffer1[0] = '\0';
760
 
    empty_lines = 0;
761
 
    while (!feof(in_file->file)
762
 
           && empty_lines < 2) {
763
 
      /* Test for REPEAT */
764
 
      b1 = buffer;
765
 
      p1 = LONGTXT_ROW_REPEAT1_FORMAT;
766
 
      len = sizeof(LONGTXT_ROW_REPEAT1_FORMAT) -1;
767
 
      if(!strncmp(b1, p1, len)) {
768
 
        break;
769
 
      }
770
 
 
771
 
      /* Test for ALARM */
772
 
      b1 = buffer;
773
 
      p1 = LONGTXT_ROW_ALARM1_FORMAT;
774
 
      len = sizeof(LONGTXT_ROW_ALARM1_FORMAT) -1;
775
 
      if(!strncmp(b1, p1, len)) {
776
 
        break;
777
 
      }
778
 
 
779
 
      /* Test for NOTE */
780
 
      b1 = buffer;
781
 
      p1 = LONGTXT_ROW_NOTE_FORMAT;
782
 
      len = sizeof(LONGTXT_ROW_NOTE_FORMAT) -1;
783
 
      if(!strncmp(b1, p1, len)) {
784
 
        break;
785
 
      }
786
 
 
787
 
      /* Test for UNTIMED_EVENT */
788
 
      b1 = buffer;
789
 
      p1 = LONGTXT_ROW_UNTIMED1_FORMAT;
790
 
      len = sizeof(LONGTXT_ROW_UNTIMED1_FORMAT) -1;
791
 
      if(!strncmp(b1, p1, len)) {
792
 
        break;
793
 
      }
794
 
 
795
 
      /* Test for APOINTMENT */
796
 
      b1 = buffer;
797
 
      p1 = LONGTXT_ROW_APPOINTMENT1_FORMAT;
798
 
      len = sizeof(LONGTXT_ROW_APPOINTMENT1_FORMAT) -1;
799
 
      if(!strncmp(b1, p1, len)) {
800
 
        break;
801
 
      }
802
 
 
803
 
      /* If we are here, then this line is still part of the description */
804
 
 
805
 
      /* Check for empty line
806
 
       * (check is done after exit tests, to allow to remove trailing
807
 
       * newlines)
808
 
       */
809
 
      if (buffer[0] == '\n') {
810
 
        empty_lines++;
811
 
      }
812
 
      else {
813
 
        empty_lines = 0;
814
 
      }
815
 
 
816
 
      /* Add line to description */
817
 
      strncat(buffer1, buffer, sizeof(buffer1)-strlen(buffer1)-1);
818
 
 
819
 
      /* Read next line */
820
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
821
 
    } /* while */
822
 
    /* Remove up to 2 trailing newlines from description
823
 
     */
824
 
    /* Less then 2 empty lines? Then end without newline */ 
825
 
    if (empty_lines < 2)
826
 
      *(buffer1 + strlen(buffer1) - empty_lines -1) = '\0';
827
 
    else
828
 
      *(buffer1 + strlen(buffer1) - empty_lines) = '\0';
829
 
 
830
 
    if (strlen(buffer1)<=0) {
831
 
      warn_message("Description was empty when reading from input file line %d\n\n",
832
 
                   in_file->line_no);
833
 
      break;
834
 
    }
835
 
    a.description = strdup(buffer1);
836
 
    if (a.description == NULL)
837
 
      error_message("Out of memory: strdup failed when reading description from input file line %d\n\n",
838
 
                    in_file->line_no);
839
 
 
840
 
 
841
 
    /* Test for REPEAT */
842
 
    b1 = buffer;
843
 
    p1 = LONGTXT_ROW_REPEAT1_FORMAT;
844
 
    len = sizeof(LONGTXT_ROW_REPEAT1_FORMAT) -1;
845
 
    if (feof(in_file->file)
846
 
        || strncmp(b1, p1, len)) {
847
 
      /* No REPEAT */
848
 
      a.repeatType = (enum repeatTypes) 0;
849
 
      a.repeatForever = 1;
850
 
      a.repeatFrequency = 0;
851
 
      a.repeatDay = (enum DayOfMonthType) 0;
852
 
      for(i=0;i<7;i++)
853
 
        a.repeatDays[i] = 0;
854
 
      a.repeatWeekstart = 0;
855
 
    }
856
 
    else {
857
 
      /* Found REPEAT */
858
 
      b1 += len;
859
 
 
860
 
      /* Init repeat data */
861
 
      a.repeatType = (enum repeatTypes) 0;
862
 
      a.repeatForever = 1;
863
 
      a.repeatFrequency = 0;
864
 
      a.repeatDay = (enum DayOfMonthType) 0;
865
 
      for(i=0;i<7;i++)
866
 
        a.repeatDays[i] = 0;
867
 
      a.repeatWeekstart = 0;
868
 
 
869
 
      /* Read repeat start date
870
 
       * (assuming here that the first character of the next text string will
871
 
       * always contain the separator)
872
 
       */
873
 
      b2 = data_index(b1, LONGTXT_ROW_REPEAT2_FORMAT[0]);
874
 
      len = b2-b1;
875
 
      if (len >= sizeof(date_buffer))
876
 
        error_message("Date_buffer size: Can not read repeat start date from input file line %d\n\n",
877
 
                      in_file->line_no);
878
 
      strncpy(date_buffer, b1, len);
879
 
      date_buffer[len] = '\0';
880
 
      t = read_iso_date_str1 (date_buffer);
881
 
      if (t == -1) {
882
 
        warn_message("Can not parse repeat start date from input file line %d\n\n",
883
 
                     in_file->line_no);
884
 
        break;
885
 
      }
886
 
      b1 = b2;
887
 
      tm = *localtime(&t);
888
 
      if (tm.tm_year != a.begin.tm_year
889
 
          || tm.tm_mon != a.begin.tm_mon
890
 
          || tm.tm_mday != a.begin.tm_mday) {
891
 
        warn_message("Repeat start date deviates from event start date, input file line %d\n\n",
892
 
                     in_file->line_no);
893
 
        break;
894
 
      }
895
 
 
896
 
      /* Find repeat end date */
897
 
      p1 = LONGTXT_ROW_REPEAT2_FORMAT;
898
 
      len = sizeof(LONGTXT_ROW_REPEAT2_FORMAT) -1;
899
 
      if(strncmp(b1, p1, len)) {
900
 
        warn_message("Can not find repeat end date from input file line %d\n\n",
901
 
                     in_file->line_no);
902
 
        break;
903
 
      }
904
 
      b1 += len;
905
 
 
906
 
      /* Read repeat end date
907
 
       * (assuming here that the first character of the next text string will
908
 
       * always contain the separator)
909
 
       */
910
 
      b2 = data_index(b1, LONGTXT_ROW_REPEAT3_FORMAT[0]);
911
 
      len = b2-b1;
912
 
      if (len >= sizeof(date_buffer))
913
 
        error_message("Date_buffer size: Can not parse repeat end date from input file line %d\n\n",
914
 
                      in_file->line_no);
915
 
      if (!strncmp(b1, LONGTXT_ROW_REPEAT_FOREVER_CONST, len)) {
916
 
        /* Repeat forever */
917
 
        a.repeatForever = 1;
918
 
        b1 += len;
919
 
      }
920
 
      else {
921
 
        /* Repeat until end date */
922
 
        a.repeatForever = 0;
923
 
        strncpy(date_buffer, b1, len);
924
 
        date_buffer[len] = '\0';
925
 
        t = read_iso_date_str1 (date_buffer);
926
 
        if (t == -1) {
927
 
          warn_message("Can not parse repeat end date from input file line %d\n\n",
928
 
                       in_file->line_no);
929
 
          break;
930
 
        }
931
 
        b1 = b2;
932
 
        a.repeatEnd = *localtime(&t);
933
 
      }
934
 
 
935
 
      /* Find repeat type */
936
 
      p1 = LONGTXT_ROW_REPEAT3_FORMAT;
937
 
      len = sizeof(LONGTXT_ROW_REPEAT3_FORMAT) -1;
938
 
      if(strncmp(b1, p1, len)) {
939
 
        warn_message("Can not find repeat type in input file line %d\n\n",
940
 
                     in_file->line_no);
941
 
        break;
942
 
      }
943
 
      b1 += len;
944
 
 
945
 
      /* Read repeat type
946
 
       * (assuming here that the first character of the next text string will
947
 
       * always contain the separator)
948
 
       */
949
 
      if (!strncmp(b1, LONGTXT_ROW_REPEAT_DAILY_CONST,
950
 
                   sizeof(LONGTXT_ROW_REPEAT_DAILY_CONST) -1)) {
951
 
        /* Repeat daily */
952
 
        a.repeatType = repeatDaily;
953
 
        b1 += sizeof(LONGTXT_ROW_REPEAT_DAILY_CONST) -1;
954
 
      }
955
 
      else if (!strncmp(b1, LONGTXT_ROW_REPEAT_WEEKLY_CONST,
956
 
                        sizeof(LONGTXT_ROW_REPEAT_WEEKLY_CONST) -1)) {
957
 
        /* Repeat weekly */
958
 
        a.repeatType = repeatWeekly;
959
 
        b1 += sizeof(LONGTXT_ROW_REPEAT_WEEKLY_CONST) -1;
960
 
      }
961
 
      else if (!strncmp(b1, LONGTXT_ROW_REPEAT_MONTHLY_LAST_WEEK_CONST,
962
 
                        sizeof(LONGTXT_ROW_REPEAT_MONTHLY_LAST_WEEK_CONST) -1)) {
963
 
        /* Repeat monthly on a fixed weekday in the last week of the month */
964
 
        a.repeatType = repeatMonthlyByDay;
965
 
        repeat_last_week = TRUE;
966
 
        b1 += sizeof(LONGTXT_ROW_REPEAT_MONTHLY_LAST_WEEK_CONST) -1;
967
 
      }
968
 
      else if (!strncmp(b1, LONGTXT_ROW_REPEAT_MONTHLY_WEEKDAY_CONST,
969
 
                        sizeof(LONGTXT_ROW_REPEAT_MONTHLY_WEEKDAY_CONST) -1)) {
970
 
        /* Repeat monthly on a fixed weekday */
971
 
        a.repeatType = repeatMonthlyByDay;
972
 
        repeat_last_week = FALSE;
973
 
        b1 += sizeof(LONGTXT_ROW_REPEAT_MONTHLY_WEEKDAY_CONST) -1;
974
 
      }
975
 
      else if (!strncmp(b1, LONGTXT_ROW_REPEAT_MONTHLY_CONST,
976
 
                        sizeof(LONGTXT_ROW_REPEAT_MONTHLY_CONST) -1)) {
977
 
        /* Repeat monthly */
978
 
        a.repeatType = repeatMonthlyByDate;
979
 
        b1 += sizeof(LONGTXT_ROW_REPEAT_MONTHLY_CONST) -1;
980
 
      }
981
 
      else if (!strncmp(b1, LONGTXT_ROW_REPEAT_YEARLY_CONST,
982
 
                        sizeof(LONGTXT_ROW_REPEAT_YEARLY_CONST) -1)) {
983
 
        /* Repeat yearly */
984
 
        a.repeatType = repeatYearly;
985
 
        b1 += sizeof(LONGTXT_ROW_REPEAT_YEARLY_CONST) -1;
986
 
      }
987
 
      else {
988
 
        warn_message("Encountered unknown repeat type from input file line %d\n\n",
989
 
                     in_file->line_no);
990
 
        break;
991
 
      }
992
 
 
993
 
      /* Find end of repeat type */
994
 
      p1 = LONGTXT_ROW_REPEAT4_FORMAT;
995
 
      len = sizeof(LONGTXT_ROW_REPEAT4_FORMAT) -1;
996
 
      if(strncmp(b1, p1, len)) {
997
 
        warn_message("Can not find end of repeat type from input file line %d\n\n",
998
 
                     in_file->line_no);
999
 
        break;
1000
 
      }
1001
 
      b1 += len;
1002
 
 
1003
 
 
1004
 
      /* Read repeat type specific parameters */
1005
 
      /* Repeat daily
1006
 
       *
1007
 
       * Means on proceeding days:
1008
 
       * Today, tomorrow,...
1009
 
       */
1010
 
      if(a.repeatType == repeatDaily) {
1011
 
        /* On the specified day... */
1012
 
        /* No parameters to read */
1013
 
      }
1014
 
      else {
1015
 
        /* All other repeat types have repeat type specific data */
1016
 
        /* Find start of repeat type specific data */
1017
 
        p1 = LONGTXT_ROW_REPEAT_PARAM1_FORMAT;
1018
 
        len = sizeof(LONGTXT_ROW_REPEAT_PARAM1_FORMAT) -1;
1019
 
        if(strncmp(b1, p1, len)) {
1020
 
          warn_message("Can not find repeat type specific data from input file line %d\n\n",
1021
 
                       in_file->line_no);
1022
 
          break;
1023
 
        }
1024
 
        b1 += len;
1025
 
 
1026
 
        b2 = data_index(b1, LONGTXT_ROW_REPEAT_PARAM2_FORMAT[0]);
1027
 
        len = b2-b1;
1028
 
        if (len >= sizeof(buffer1)) {
1029
 
          warn_message("buffer1 size: Can not parse repeat type specific data from input file line %d\n\n",
1030
 
                       in_file->line_no);
1031
 
          break;
1032
 
        }
1033
 
        strncpy(repeatparam, b1, len);
1034
 
        repeatparam[len] = '\0';
1035
 
        b1 = b2;
1036
 
 
1037
 
        /* Find end of repeatparams */
1038
 
        p1 = LONGTXT_ROW_REPEAT_PARAM2_FORMAT;
1039
 
        len = sizeof(LONGTXT_ROW_REPEAT_PARAM2_FORMAT) -1;
1040
 
        if(strncmp(b1, p1, len)) {
1041
 
          warn_message("Unexpected end of line reading from input file line %d\n\n",
1042
 
                       in_file->line_no);
1043
 
          break;
1044
 
        }
1045
 
        b1 += len;
1046
 
        /* Now repeatparam contains the repeat type specific data */
1047
 
 
1048
 
 
1049
 
        /* Repeat monthly by date
1050
 
         *
1051
 
         * Means always on the same date number (e.g. 17) in every month:
1052
 
         * 17th of January, 17th of February, 17th of March,...
1053
 
         */
1054
 
        if(a.repeatType == repeatMonthlyByDate) {
1055
 
          /* On the x of every month */
1056
 
 
1057
 
          /* Parsing repeat type specific data */
1058
 
          num_read = sscanf (repeatparam,
1059
 
                             LONGTXT_ROW_REPEAT_MONTHLY_FORMAT,
1060
 
                             &mday);
1061
 
          if (num_read != 1) {
1062
 
            warn_message("Can not parse repeat type specific data from input file line %d\n\n",
1063
 
                         in_file->line_no);
1064
 
            break;
1065
 
          }
1066
 
          if (mday != a.begin.tm_mday) {
1067
 
            warn_message("Monthly repeat day differs from start day reading from input file line %d\n\n",
1068
 
                         in_file->line_no);
1069
 
            break;
1070
 
          }
1071
 
        }
1072
 
 
1073
 
 
1074
 
        /* Repeat weekly
1075
 
         *
1076
 
         * Means always on the same weekday in every week:
1077
 
         * Tuesday this week, Tuesday next week,...
1078
 
         */
1079
 
        else if(a.repeatType == repeatWeekly)
1080
 
          /* On the chosen days of the week */
1081
 
          {
1082
 
            int k;
1083
 
 
1084
 
            /* Parsing repeat type specific data */
1085
 
            b2 = repeatparam;
1086
 
            len = strlen(repeatparam);
1087
 
            /* Init weekdays */
1088
 
            for(k=0;k<7;k++) {
1089
 
              a.repeatDays[k] = 0;
1090
 
            }
1091
 
            /* process whole repeat param string */
1092
 
            while (len > 0) {
1093
 
              if (isspace(*b2)
1094
 
                  || *b2 == ',') {
1095
 
                /* skip separator */
1096
 
                b2++;
1097
 
                len--;
1098
 
                continue;
1099
 
              }
1100
 
              /* Found week day name, now trying to find index */
1101
 
              k = weekday2int(b2);
1102
 
              if (k>=0) {
1103
 
                /* Found index of week day */
1104
 
                a.repeatDays[k] = 1;
1105
 
                b2 += WEEKDAY_LEN;
1106
 
                len -= WEEKDAY_LEN;
1107
 
                continue;
1108
 
              }
1109
 
              else {
1110
 
                /* Unknown week day */
1111
 
                strncpy(buffer1, b2, WEEKDAY_LEN);
1112
 
                buffer1[WEEKDAY_LEN]= '\0';
1113
 
                warn_message("Unknown week day <%s> found reading from input file line %d\n\n",
1114
 
                             buffer1,
1115
 
                             in_file->line_no);
1116
 
                break;
1117
 
              }
1118
 
            } /* while */
1119
 
          } /* else repeat weekly */
1120
 
 
1121
 
          
1122
 
        /* Repeat monthly by weekday
1123
 
         *
1124
 
         * Means always on the same weekday in every month.
1125
 
         * Comes in two flavors:
1126
 
         * - weekday of last week
1127
 
         * - weekday of first, second, third, or forth week
1128
 
         */
1129
 
        else if(a.repeatType == repeatMonthlyByDay) {
1130
 
          int day;
1131
 
          int weekday;
1132
 
 
1133
 
          /* Repeat monthly by weekday for last week
1134
 
           *
1135
 
           * Means always on the same weekday in the last week in every month:
1136
 
           * Last Tuesday this month, last Tuesday next month,...
1137
 
           */
1138
 
          if(repeat_last_week == TRUE) {
1139
 
            num_read = sscanf (repeatparam,
1140
 
                               LONGTXT_ROW_REPEAT_MONTHLY_LAST_WEEK_FORMAT,
1141
 
                               &buffer1,
1142
 
                               &day);
1143
 
            if (num_read < 1
1144
 
                || num_read > 2) {
1145
 
              warn_message("Can not parse weekday repeat specific data from input file line %d\n\n",
1146
 
                           in_file->line_no);
1147
 
              break;
1148
 
            }
1149
 
            weekday = weekday2int(buffer1);
1150
 
            if (weekday < 0) {
1151
 
              /* Unknown week day */
1152
 
              strncpy(buffer1, b2, WEEKDAY_LEN);
1153
 
              buffer1[WEEKDAY_LEN]= '\0';
1154
 
              warn_message("Unknown week day <%s> found reading from input file line %d\n\n",
1155
 
                           buffer1,
1156
 
                           in_file->line_no);
1157
 
              break;
1158
 
            }
1159
 
            /* day should be 1, since only the last week is possible,
1160
 
             * but can not be bothered to check for this...
1161
 
             */
1162
 
            a.repeatDay = domLastSun + weekday;
1163
 
          }
1164
 
 
1165
 
 
1166
 
          /* Repeat monthly by weekday not in last week
1167
 
           *
1168
 
           * Means always on the same weekday in the same week in every month:
1169
 
           * Second Tuesday this month, second Tuesday next month,...
1170
 
           */
1171
 
          else {
1172
 
            num_read = sscanf (repeatparam,
1173
 
                               LONGTXT_ROW_REPEAT_MONTHLY_WEEKDAY_FORMAT,
1174
 
                               &buffer1,
1175
 
                               &day);
1176
 
            if (num_read != 2) {
1177
 
              warn_message("Can not parse weekday repeat specific data from input file line %d\n\n",
1178
 
                           in_file->line_no);
1179
 
              break;
1180
 
            }
1181
 
            weekday = weekday2int(buffer1);
1182
 
            if (weekday < 0) {
1183
 
              /* Unknown week day */
1184
 
              strncpy(buffer1, b2, WEEKDAY_LEN);
1185
 
              buffer1[WEEKDAY_LEN]= '\0';
1186
 
              warn_message("Unknown week day <%s> found reading from input file line %d\n\n",
1187
 
                           buffer1,
1188
 
                           in_file->line_no);
1189
 
              break;
1190
 
            }
1191
 
            if (day <1 || day > 4) {
1192
 
              warn_message("Unknown week number <%d> found reading from input file line %d\n\n",
1193
 
                           day,
1194
 
                           in_file->line_no);
1195
 
              break;
1196
 
            }
1197
 
            a.repeatDay = (day -1)*7 + weekday;
1198
 
          } /* else repeat monthly by weekday not in last week */
1199
 
        } /* else repeat monthly by weekday */
1200
 
 
1201
 
 
1202
 
        /* Repeat yearly
1203
 
         *
1204
 
         * Means always on the same date in every year:
1205
 
         * 27th October this year, 27th October next year,...
1206
 
         */
1207
 
        else if(a.repeatType == repeatYearly) {
1208
 
          /* On one day each year */
1209
 
          t = read_iso_date_str1 (repeatparam);
1210
 
          if (t == -1) {
1211
 
            warn_message("Can not parse yearly repeat date from input file line %d\n\n",
1212
 
                         in_file->line_no);
1213
 
            break;
1214
 
          }
1215
 
          tm = *localtime(&t);
1216
 
          if (tm.tm_mon != a.begin.tm_mon
1217
 
              || tm.tm_mday != a.begin.tm_mday) {
1218
 
            warn_message("Yearly repeat date deviates from event start date, input file line %d\n\n",
1219
 
                         in_file->line_no);
1220
 
            break;
1221
 
          }
1222
 
        } /* else repeat yearly */
1223
 
 
1224
 
      } /* end else for repeat types with specific data */
1225
 
 
1226
 
 
1227
 
      /* Test for repeat frequency */
1228
 
      p1 = LONGTXT_ROW_REPEAT_FREQUENCY1_FORMAT;
1229
 
      len = sizeof(LONGTXT_ROW_REPEAT_FREQUENCY1_FORMAT) -1;
1230
 
      if(strncmp(b1, p1, len)) {
1231
 
        /* No frequency found */
1232
 
        /* Set default: frequency = 1 */
1233
 
        a.repeatFrequency = 1;
1234
 
      }
1235
 
      else {
1236
 
        /* Found frequency */
1237
 
        b1 += len;
1238
 
 
1239
 
        /* Read frequency */
1240
 
        a.repeatFrequency = strtol(b1, &b2, 0);
1241
 
        b1 = b2;
1242
 
 
1243
 
        /* Find end of repeat frequency */
1244
 
        p1 = LONGTXT_ROW_REPEAT_FREQUENCY2_FORMAT;
1245
 
        len = sizeof(LONGTXT_ROW_REPEAT_FREQUENCY2_FORMAT) -1;
1246
 
        if(strncmp(b1, p1, len)) {
1247
 
          warn_message("Unexpected end of line reading frequency from input file line %d\n\n",
1248
 
                       in_file->line_no);
1249
 
          break;
1250
 
        }
1251
 
        b1 += len;
1252
 
      }
1253
 
 
1254
 
 
1255
 
      /* Test for repeat weekstart */
1256
 
      p1 = LONGTXT_ROW_REPEAT_WEEKSTART1_FORMAT;
1257
 
      len = sizeof(LONGTXT_ROW_REPEAT_WEEKSTART1_FORMAT) -1;
1258
 
      if(strncmp(b1, p1, len)) {
1259
 
        /* No weekstart found */
1260
 
        /* Set default: weekstart = 0 */
1261
 
        a.repeatWeekstart = 0;
1262
 
      }
1263
 
      else {
1264
 
        /* Found weekstart */
1265
 
        b1 += len;
1266
 
 
1267
 
        /* Read weekstart */
1268
 
        a.repeatWeekstart = strtol(b1, &b2, 0);
1269
 
        b1 = b2;
1270
 
 
1271
 
 
1272
 
        b2 = data_index(b1, LONGTXT_ROW_REPEAT_PARAM2_FORMAT[0]);
1273
 
        len = b2-b1;
1274
 
        if (len >= sizeof(buffer1))
1275
 
          error_message("buffer1 size: Can not parse repeat type specific data from input file line %d\n\n",
1276
 
                        in_file->line_no);
1277
 
        /* Found week day name, now trying to find index */
1278
 
        a.repeatWeekstart = weekday2int(b1);
1279
 
        if (a.repeatWeekstart<0) {
1280
 
          /* Unknown week day */
1281
 
          strncpy(buffer1, b2, WEEKDAY_LEN);
1282
 
          buffer1[WEEKDAY_LEN]= '\0';
1283
 
          warn_message("Unknown week day <%s> found reading from input file line %d\n\n",
1284
 
                       buffer1,
1285
 
                       in_file->line_no);
1286
 
          break;
1287
 
        }
1288
 
        b1 = b2;
1289
 
 
1290
 
 
1291
 
        /* Find end of repeat weekstart */
1292
 
        p1 = LONGTXT_ROW_REPEAT_WEEKSTART2_FORMAT;
1293
 
        len = sizeof(LONGTXT_ROW_REPEAT_WEEKSTART2_FORMAT) -1;
1294
 
        if(strncmp(b1, p1, len)) {
1295
 
          warn_message("Unexpected end of line reading weekstart from input file line %d\n\n",
1296
 
                       in_file->line_no);
1297
 
          break;
1298
 
        }
1299
 
        b1 += len;
1300
 
      }
1301
 
 
1302
 
 
1303
 
 
1304
 
      /* Test for repeat exceptions (omissions) */
1305
 
      p1 = LONGTXT_ROW_REPEAT_OMIT1_FORMAT;
1306
 
      len = sizeof(LONGTXT_ROW_REPEAT_OMIT1_FORMAT) -1;
1307
 
      if(strncmp(b1, p1, len)) {
1308
 
        /* No exceptions for this event */
1309
 
        a.exceptions = 0;
1310
 
        a.exception = NULL;
1311
 
      }
1312
 
      else {
1313
 
        /* Found exceptions */
1314
 
        b1 += len;
1315
 
 
1316
 
        /* Find out how many exceptions for proper malloc */
1317
 
        j = 0;
1318
 
        /* Look for separator */
1319
 
        b2 = data_index(b1, LONGTXT_ROW_REPEAT_OMIT2_FORMAT[0]);
1320
 
        while (b2 != NULL
1321
 
               && strlen(b2)>0
1322
 
               && *b2 != '\n') {
1323
 
          /* Found end separator */
1324
 
          /* Only count as success when end separator was found */
1325
 
          j++;
1326
 
 
1327
 
          /* More exceptions to be found ? */
1328
 
          p1 = LONGTXT_ROW_REPEAT_OMIT2_FORMAT;
1329
 
          len = sizeof(LONGTXT_ROW_REPEAT_OMIT2_FORMAT) -1;
1330
 
          if(!strncmp(b2, p1, len)) {
1331
 
            /* Found another exception */
1332
 
 
1333
 
            /* Now look for its end separator */
1334
 
            b2 = data_index(b2 +1, LONGTXT_ROW_REPEAT_OMIT2_FORMAT[0]);
1335
 
            if (b2 == NULL)
1336
 
              /* No more separator */
1337
 
              break;
1338
 
          }
1339
 
          else {
1340
 
            /* No more exceptions */
1341
 
            break;
1342
 
          }
1343
 
        } /* while */
1344
 
 
1345
 
        /* malloc */
1346
 
        a.exceptions = j;
1347
 
        a.exception = calloc(a.exceptions, sizeof(struct tm));
1348
 
 
1349
 
        /* Now really read exceptions */
1350
 
        b2 = data_index(b1, LONGTXT_ROW_REPEAT_OMIT2_FORMAT[0]);
1351
 
        j = 0;
1352
 
 
1353
 
        /* Read exception dates */
1354
 
        while (b2 != NULL
1355
 
               && strlen(b2)>0
1356
 
               && *b2 != '\n') {
1357
 
          /* Found end separator */
1358
 
 
1359
 
          /* Read omission date */
1360
 
          len = b2-b1;
1361
 
          if (len >= sizeof(date_buffer))
1362
 
            error_message("Date_buffer size: Can not read omit date from input file line %d\n\n",
1363
 
                          in_file->line_no);
1364
 
          strncpy(date_buffer, b1, len);
1365
 
          date_buffer[len] = '\0';
1366
 
          t = read_iso_date_str1 (date_buffer);
1367
 
          if (t == -1) {
1368
 
            warn_message("Can not parse omit date <%s> from input file line %d\n\n",
1369
 
                         date_buffer,
1370
 
                         in_file->line_no);
1371
 
            break;
1372
 
          }
1373
 
          b1 = b2;
1374
 
          a.exception[j] = *localtime(&t);
1375
 
 
1376
 
          /* Only count as success when successfully processed */
1377
 
          j++;
1378
 
 
1379
 
          /* More exceptions to be found ? */
1380
 
          p1 = LONGTXT_ROW_REPEAT_OMIT2_FORMAT;
1381
 
          len = sizeof(LONGTXT_ROW_REPEAT_OMIT2_FORMAT) -1;
1382
 
          if(!strncmp(b2, p1, len)) {
1383
 
            /* Found another exception */
1384
 
            b1 += len;
1385
 
 
1386
 
            /* Now look for its end separator */
1387
 
            b2 = data_index(b2 +1, LONGTXT_ROW_REPEAT_OMIT2_FORMAT[0]);
1388
 
            if (b2 == NULL)
1389
 
              /* No more separator */
1390
 
              break;
1391
 
          }
1392
 
          else {
1393
 
            /* No more exceptions */
1394
 
            break;
1395
 
          } /* if found one exception */
1396
 
        } /* while */
1397
 
 
1398
 
        /* Find end of repeat exceptions */
1399
 
        p1 = LONGTXT_ROW_REPEAT_OMIT3_FORMAT;
1400
 
        len = sizeof(LONGTXT_ROW_REPEAT_OMIT3_FORMAT) -1;
1401
 
        if(strncmp(b1, p1, len)) {
1402
 
          warn_message("Unexpected end of line reading omit dates from input file line %d\n\n",
1403
 
                       in_file->line_no);
1404
 
          break;
1405
 
        }
1406
 
        b1 += len;
1407
 
        /* should be at end of line now */
1408
 
      } /* End of test for repeat exceptions */
1409
 
 
1410
 
 
1411
 
      /* Read next line */
1412
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
1413
 
    } /* end else for REPEAT */
1414
 
 
1415
 
 
1416
 
    /* Test for ALARM */
1417
 
    b1 = buffer;
1418
 
    p1 = LONGTXT_ROW_ALARM1_FORMAT;
1419
 
    len = sizeof(LONGTXT_ROW_ALARM1_FORMAT) -1;
1420
 
    if(feof(in_file->file)
1421
 
       || strncmp(b1, p1, len)) {
1422
 
      /* No ALARM */
1423
 
      a.alarm = 0;
1424
 
      a.advance = 0;
1425
 
      a.advanceUnits = 0;
1426
 
    }
1427
 
    else {
1428
 
      /* Found ALARM */
1429
 
      b1 += len;
1430
 
 
1431
 
      a.alarm = 1;
1432
 
 
1433
 
      /* alarm how much before */
1434
 
      num_read = sscanf (b1,
1435
 
                         LONGTXT_ROW_ALARM2_FORMAT,
1436
 
                         &a.advance,
1437
 
                         &buffer1);
1438
 
      if (num_read != 2) {
1439
 
        warn_message("Can not read alarm advance options from input file line %d\n\n",
1440
 
                     in_file->line_no);
1441
 
        break;
1442
 
      }
1443
 
      b2 = buffer1;
1444
 
      p1 = LONGTXT_ROW_ALARM_MIN_CONST;
1445
 
      len = sizeof(LONGTXT_ROW_ALARM_MIN_CONST) -1;
1446
 
      if(!strncmp(b2, p1, len)) {
1447
 
        a.advanceUnits = advMinutes;
1448
 
      }
1449
 
      else {
1450
 
        p1 = LONGTXT_ROW_ALARM_HOURS_CONST;
1451
 
        len = sizeof(LONGTXT_ROW_ALARM_HOURS_CONST) -1;
1452
 
        if(!strncmp(b2, p1, len)) {
1453
 
          a.advanceUnits = advHours;
1454
 
        }
1455
 
        else {
1456
 
          p1 = LONGTXT_ROW_ALARM_DAYS_CONST;
1457
 
          len = sizeof(LONGTXT_ROW_ALARM_DAYS_CONST) -1;
1458
 
          if(!strncmp(b2, p1, len)) {
1459
 
            a.advanceUnits = advDays;
1460
 
          }
1461
 
          else {
1462
 
            warn_message("Can not understand alarm advance unit <%s> from input file line %d\n\n",
1463
 
                         b2,
1464
 
                         in_file->line_no);
1465
 
            break;
1466
 
          } /* advance days */
1467
 
        } /* advance hours */
1468
 
      } /* advance minutes */
1469
 
 
1470
 
 
1471
 
      /* Read next line */
1472
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
1473
 
    } /* ALARM */
1474
 
 
1475
 
 
1476
 
    /* Find NOTE */
1477
 
    p1 = LONGTXT_ROW_NOTE_FORMAT;
1478
 
    len = sizeof(LONGTXT_ROW_NOTE_FORMAT) -1;
1479
 
    if(feof(in_file->file)
1480
 
       || strncmp(buffer, p1, len)) {
1481
 
      /* No NOTE */
1482
 
      a.note = NULL;
1483
 
    }
1484
 
    else {
1485
 
      /* Found NOTE */
1486
 
      /* should be at end of line now */
1487
 
 
1488
 
      /* Read next line */
1489
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
1490
 
 
1491
 
      /* Read note until encountering two empty lines or
1492
 
       * next UNTIMED_EVENT, or APPOINTMENT
1493
 
       */
1494
 
      buffer1[0] = '\0';
1495
 
      empty_lines = 0;
1496
 
      while (!feof(in_file->file)
1497
 
             && empty_lines < 2) {
1498
 
        /* Test for UNTIMED_EVENT */
1499
 
        b1 = buffer;
1500
 
        p1 = LONGTXT_ROW_UNTIMED1_FORMAT;
1501
 
        len = sizeof(LONGTXT_ROW_UNTIMED1_FORMAT) -1;
1502
 
        if(!strncmp(b1, p1, len)) {
1503
 
          break;
1504
 
        }
1505
 
 
1506
 
        /* Test for APPOINTMENT */
1507
 
        b1 = buffer;
1508
 
        p1 = LONGTXT_ROW_APPOINTMENT1_FORMAT;
1509
 
        len = sizeof(LONGTXT_ROW_APPOINTMENT1_FORMAT) -1;
1510
 
        if(!strncmp(b1, p1, len)) {
1511
 
          break;
1512
 
        }
1513
 
 
1514
 
        /* If we are here, then this line is still part of the note */
1515
 
 
1516
 
        /* Check for empty line
1517
 
         * (check is done after exit tests, to allow to remove trailing
1518
 
         * newlines)
1519
 
         */
1520
 
        if (buffer[0] == '\n') {
1521
 
          empty_lines++;
1522
 
        }
1523
 
        else {
1524
 
          empty_lines = 0;
1525
 
        }
1526
 
 
1527
 
        /* Add line to note */
1528
 
        strncat(buffer1, buffer, sizeof(buffer1)-strlen(buffer1)-1);
1529
 
 
1530
 
        /* Read next line */
1531
 
        longtxt_read_line(buffer, sizeof(buffer), in_file);
1532
 
      }
1533
 
 
1534
 
      /* Always remove at max two trailing newlines, since two newlines
1535
 
       * separate the note from the following data.
1536
 
       */
1537
 
      /* Less then 2 empty lines? Then end without newline */ 
1538
 
      if (empty_lines < 2)
1539
 
        *(buffer1 + strlen(buffer1) - empty_lines -1) = '\0';
1540
 
      else
1541
 
        *(buffer1 + strlen(buffer1) - empty_lines) = '\0';
1542
 
 
1543
 
      if (strlen(buffer1)<=0) {
1544
 
        warn_message("Note was empty when reading from input file line %d\n\n",
1545
 
                     in_file->line_no);
1546
 
        break;
1547
 
      }
1548
 
      a.note = strdup(buffer1);
1549
 
      if (a.note == NULL)
1550
 
        error_message("Out of memory: strdup failed when reading note from input file line %d\n\n",
1551
 
                      in_file->line_no);
1552
 
    } /* Find NOTE */
1553
 
 
1554
 
    /* Skip empty lines to position for next row */
1555
 
    while (!feof(in_file->file)
1556
 
           && buffer[0] == '\n') {
1557
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
1558
 
    }
1559
 
 
1560
 
    /* Put last line back, to be read on next read attempt */
1561
 
    if (!feof(in_file->file))
1562
 
      longtxt_pushback_line(buffer, in_file);
1563
 
 
1564
 
 
1565
 
 
1566
 
    /* Set datebook row data */
1567
 
    setRowRecordNum(row, record_num);
1568
 
    setRowUid(row, uid);
1569
 
    setRowAttributes(row, attributes);
1570
 
    setRowCategory(row, category);
1571
 
    setRowAppointment(row, a);
1572
 
    setRowIsValid(row, TRUE);
1573
 
 
1574
 
    /* increment counters */
1575
 
    in_file->num_recs++;
1576
 
    in_file->next_rec++;
1577
 
 
1578
 
    /* Update statistics */
1579
 
    in_file->records_read++;
1580
 
  } while (FALSE);
1581
 
 
1582
 
  /* Debug */
1583
 
  debug_message("Leaving longtxt_read_row\n");
1584
 
}
1585
 
 
1586
 
 
1587
 
 
1588
 
/* For writing */
1589
 
 
1590
 
/* Write an appointment record */
1591
 
void
1592
 
longtxt_write_row (struct longtxt_file_data * out_file, struct header_data * header, struct row_data * row)
1593
 
{
1594
 
  int j;
1595
 
  struct AppointmentAppInfo aai;
1596
 
  struct Appointment a;
1597
 
  int attributes;
1598
 
  int category;
1599
 
  unsigned long uid;
1600
 
  int record_num;
1601
 
 
1602
 
  char date1_buffer[50];
1603
 
  char time1_buffer[50];
1604
 
  char date2_buffer[50];
1605
 
  char time2_buffer[50];
1606
 
  char repeatType[30];
1607
 
  char repeatparam[30];
1608
 
  char alarmparam[80];
1609
 
  int repeatparam_len = 0;
1610
 
 
1611
 
 
1612
 
  /* Debug */
1613
 
  debug_message("Entering longtxt_write_row\n");
1614
 
 
1615
 
  if (!getRowIsValid(row))
1616
 
    error_message("Can not write invalid row.\n");
1617
 
 
1618
 
  /* Get datebook header data */
1619
 
  aai = header->aai;
1620
 
 
1621
 
  /* Get datebook row data */
1622
 
  record_num = getRowRecordNum(row);
1623
 
  uid = getRowUid(row);
1624
 
  attributes = getRowAttributes(row);
1625
 
  category = getRowCategory(row);
1626
 
  a = getRowAppointment(row);
1627
 
 
1628
 
 
1629
 
  /* Write datebook row data */
1630
 
  /* Event type/time */
1631
 
  if(a.event) {
1632
 
    write_human_date_str (mktime(&a.begin), date1_buffer, sizeof(date1_buffer));
1633
 
    longtxt_write(out_file, "%s%lu%s%s%s",
1634
 
                  LONGTXT_ROW_UNTIMED1_FORMAT,
1635
 
                  uid,
1636
 
                  LONGTXT_ROW_UNTIMED2_FORMAT,
1637
 
                  date1_buffer,
1638
 
                  LONGTXT_ROW_UNTIMED3_FORMAT);
1639
 
    longtxt_write_str(out_file, "\n");
1640
 
  }
1641
 
  else {
1642
 
    write_human_full_time_str (mktime(&a.begin), time1_buffer, sizeof(time1_buffer));
1643
 
    write_human_full_time_str (mktime(&a.end), time2_buffer, sizeof(time2_buffer));
1644
 
    longtxt_write(out_file, "%s%lu%s%s%s%s%s",
1645
 
                  LONGTXT_ROW_APPOINTMENT1_FORMAT,
1646
 
                  uid,
1647
 
                  LONGTXT_ROW_APPOINTMENT2_FORMAT,
1648
 
                  time1_buffer,
1649
 
                  LONGTXT_ROW_APPOINTMENT3_FORMAT,
1650
 
                  time2_buffer,
1651
 
                  LONGTXT_ROW_APPOINTMENT4_FORMAT);
1652
 
    longtxt_write_str(out_file, "\n");
1653
 
  }
1654
 
 
1655
 
  /* Attributes */
1656
 
  if (attributes > 0) {
1657
 
    longtxt_write(out_file, LONGTXT_ROW_ATTRIBUTES_FORMAT,
1658
 
                  attributes,
1659
 
                  (attributes & dlpRecAttrDeleted) ? " DELETED" : "",
1660
 
                  (attributes & dlpRecAttrDirty) ? " DIRTY" : "",
1661
 
                  (attributes & dlpRecAttrBusy) ? " LOCKED" : "",
1662
 
                  (attributes & dlpRecAttrSecret) ? " PRIVATE" : "",
1663
 
                  (attributes & dlpRecAttrArchived) ? " ARCHIVED" : "");
1664
 
  }
1665
 
 
1666
 
  /* Category */
1667
 
  if (category > 0) {
1668
 
    if (header->isValid)
1669
 
      longtxt_write(out_file, LONGTXT_ROW_CATEGORY_FORMAT,
1670
 
                    category,
1671
 
                    aai.category.name[category]);
1672
 
    else
1673
 
      longtxt_write(out_file, LONGTXT_ROW_CATEGORY_FORMAT,
1674
 
                    category,
1675
 
                    "");
1676
 
  }
1677
 
 
1678
 
  /* Description */
1679
 
  /* Print it this way to properly count lines, and description is non-empty */
1680
 
  if (a.description)
1681
 
    longtxt_write_str(out_file, a.description);
1682
 
  else
1683
 
    longtxt_write_str(out_file, " ");
1684
 
  longtxt_write_str(out_file, "\n");
1685
 
 
1686
 
  /* Repeat stuff */
1687
 
  if(a.repeatType == repeatNone) {
1688
 
    /* One-time event (no repeats) */
1689
 
  }                                        
1690
 
      
1691
 
  else {
1692
 
    write_human_date_str (mktime(&a.begin), date1_buffer, sizeof(date1_buffer));
1693
 
 
1694
 
    if (a.repeatForever)
1695
 
      strncpy(date2_buffer, LONGTXT_ROW_REPEAT_FOREVER_CONST, sizeof(date2_buffer));
1696
 
    else
1697
 
      write_human_date_str (mktime(&a.repeatEnd), date2_buffer, sizeof(date2_buffer));
1698
 
 
1699
 
    if(a.repeatType == repeatDaily) {
1700
 
      strncpy(repeatType, LONGTXT_ROW_REPEAT_DAILY_CONST, sizeof(repeatType));
1701
 
    } else if(a.repeatType == repeatWeekly) {
1702
 
      strncpy(repeatType, LONGTXT_ROW_REPEAT_WEEKLY_CONST, sizeof(repeatType));
1703
 
    } else if(a.repeatType == repeatMonthlyByDay) {
1704
 
      if(a.repeatDay>=domLastSun) {
1705
 
        strncpy(repeatType, LONGTXT_ROW_REPEAT_MONTHLY_LAST_WEEK_CONST, sizeof(repeatType));
1706
 
      } else {
1707
 
        strncpy(repeatType, LONGTXT_ROW_REPEAT_MONTHLY_WEEKDAY_CONST, sizeof(repeatType));
1708
 
      }
1709
 
    } else if(a.repeatType == repeatMonthlyByDate) {
1710
 
      strncpy(repeatType, LONGTXT_ROW_REPEAT_MONTHLY_CONST, sizeof(repeatType));
1711
 
    } else if(a.repeatType == repeatYearly) {
1712
 
      strncpy(repeatType, LONGTXT_ROW_REPEAT_YEARLY_CONST, sizeof(repeatType));
1713
 
    } else {
1714
 
      strncpy(repeatType, LONGTXT_ROW_REPEAT_UNKNOWN_CONST, sizeof(repeatType));
1715
 
    }
1716
 
 
1717
 
    longtxt_write(out_file, "%s%s%s%s%s%s%s",
1718
 
                  LONGTXT_ROW_REPEAT1_FORMAT,
1719
 
                  date1_buffer,
1720
 
                  LONGTXT_ROW_REPEAT2_FORMAT,
1721
 
                  date2_buffer,
1722
 
                  LONGTXT_ROW_REPEAT3_FORMAT,
1723
 
                  repeatType,
1724
 
                  LONGTXT_ROW_REPEAT4_FORMAT);
1725
 
 
1726
 
    /* Repeat daily */
1727
 
    if(a.repeatType == repeatDaily) {
1728
 
      /* On the specified day... */
1729
 
      /* No more parameters */
1730
 
 
1731
 
      /* Repeat monthly by date */
1732
 
    } else if(a.repeatType == repeatMonthlyByDate) {
1733
 
      /* On the x of every month */
1734
 
      snprintf (repeatparam, sizeof(repeatparam),
1735
 
                LONGTXT_ROW_REPEAT_MONTHLY_FORMAT,
1736
 
                a.begin.tm_mday);
1737
 
      longtxt_write(out_file, "%s%s%s",
1738
 
                    LONGTXT_ROW_REPEAT_PARAM1_FORMAT,
1739
 
                    repeatparam,
1740
 
                    LONGTXT_ROW_REPEAT_PARAM2_FORMAT);
1741
 
 
1742
 
      /* Repeat weekly */
1743
 
    } else if(a.repeatType == repeatWeekly) {
1744
 
      int k;
1745
 
      /* On the chosen days of the week */
1746
 
      {
1747
 
        repeatparam[0] ='\0';
1748
 
        repeatparam_len = 0;
1749
 
        for(k=0;k<7;k++) {
1750
 
          if(a.repeatDays[k]) {
1751
 
            /* Use comma as separator between weekdays */
1752
 
            if (repeatparam_len > 0) {
1753
 
              repeatparam[repeatparam_len] = ',';
1754
 
              repeatparam_len++;
1755
 
              repeatparam[repeatparam_len] = '\0';
1756
 
            }
1757
 
            /* Add weekday */
1758
 
            strncat(repeatparam + repeatparam_len,
1759
 
                    int2weekday(k),
1760
 
                    sizeof(repeatparam)-repeatparam_len-1);
1761
 
            repeatparam_len = strlen(repeatparam);
1762
 
          }
1763
 
        } /* for */
1764
 
      }
1765
 
      longtxt_write(out_file, "%s%s%s",
1766
 
                    LONGTXT_ROW_REPEAT_PARAM1_FORMAT,
1767
 
                    repeatparam,
1768
 
                    LONGTXT_ROW_REPEAT_PARAM2_FORMAT);
1769
 
 
1770
 
      /* Repeat monthly by weekday */
1771
 
    } else if(a.repeatType == repeatMonthlyByDay) {
1772
 
      int day;
1773
 
      int weekday;
1774
 
                        
1775
 
      if(a.repeatDay>=domLastSun) {
1776
 
        day = 1;
1777
 
        weekday = a.repeatDay % 7;
1778
 
        snprintf (repeatparam, sizeof(repeatparam),
1779
 
                  LONGTXT_ROW_REPEAT_MONTHLY_LAST_WEEK_FORMAT,
1780
 
                  int2weekday(weekday),
1781
 
                  day);
1782
 
      } else {
1783
 
        /* day contains the week number */
1784
 
        day = a.repeatDay / 7 +1;
1785
 
        weekday = a.repeatDay % 7;
1786
 
        snprintf (repeatparam, sizeof(repeatparam),
1787
 
                  LONGTXT_ROW_REPEAT_MONTHLY_WEEKDAY_FORMAT,
1788
 
                  int2weekday(weekday),
1789
 
                  day);
1790
 
      }
1791
 
      longtxt_write(out_file, "%s%s%s",
1792
 
                    LONGTXT_ROW_REPEAT_PARAM1_FORMAT,
1793
 
                    repeatparam,
1794
 
                    LONGTXT_ROW_REPEAT_PARAM2_FORMAT);
1795
 
 
1796
 
      /* Repeat yearly */
1797
 
    } else if(a.repeatType == repeatYearly) {
1798
 
      /* On one day each year */
1799
 
      snprintf (repeatparam, sizeof(repeatparam),
1800
 
                LONGTXT_ROW_REPEAT_YEARLY_FORMAT,
1801
 
                int2month(a.begin.tm_mon),
1802
 
                a.begin.tm_mday);
1803
 
      longtxt_write(out_file, "%s%s%s",
1804
 
                    LONGTXT_ROW_REPEAT_PARAM1_FORMAT,
1805
 
                    repeatparam,
1806
 
                    LONGTXT_ROW_REPEAT_PARAM2_FORMAT);
1807
 
    }
1808
 
 
1809
 
    /* Repeat frequency */
1810
 
    if(a.repeatFrequency != 1) {
1811
 
      longtxt_write(out_file, "%s%d%s",
1812
 
                    LONGTXT_ROW_REPEAT_FREQUENCY1_FORMAT,
1813
 
                    a.repeatFrequency,
1814
 
                    LONGTXT_ROW_REPEAT_FREQUENCY2_FORMAT);
1815
 
    }
1816
 
 
1817
 
 
1818
 
    /* Repeat week start
1819
 
     *
1820
 
     * The user-decided day which starts the week
1821
 
     * (0 = Sunday, 1 = Monday).
1822
 
     * For some reason only being used for weekly events?
1823
 
     */
1824
 
    if(a.repeatWeekstart != 0) {
1825
 
      longtxt_write(out_file, "%s%s%s",
1826
 
                    LONGTXT_ROW_REPEAT_WEEKSTART1_FORMAT,
1827
 
                    int2weekday(a.repeatWeekstart),
1828
 
                    LONGTXT_ROW_REPEAT_WEEKSTART2_FORMAT);
1829
 
    }
1830
 
 
1831
 
 
1832
 
    /* List all exceptions of a repeating event */
1833
 
    if (a.exceptions) {
1834
 
      write_human_date_str (mktime(&a.exception[0]),
1835
 
                            date1_buffer, sizeof(date1_buffer));
1836
 
      longtxt_write(out_file, "%s%s",
1837
 
                    LONGTXT_ROW_REPEAT_OMIT1_FORMAT,
1838
 
                    date1_buffer);
1839
 
      /* Start from 1, since first exception has already been printed */
1840
 
      for(j=1;j<a.exceptions;j++) {
1841
 
        write_human_date_str (mktime(&a.exception[j]),
1842
 
                              date1_buffer, sizeof(date1_buffer));
1843
 
        longtxt_write(out_file, "%s%s",
1844
 
                      LONGTXT_ROW_REPEAT_OMIT2_FORMAT,
1845
 
                      date1_buffer);
1846
 
      } /* for */
1847
 
      longtxt_write_str(out_file, LONGTXT_ROW_REPEAT_OMIT3_FORMAT);
1848
 
    } /* if exceptions */
1849
 
    longtxt_write_str(out_file, "\n");
1850
 
  } /* if REPEAT */
1851
 
        
1852
 
  /* Alarm stuff */
1853
 
  if (a.alarm) {
1854
 
    /* alarm how much before */
1855
 
    snprintf(alarmparam, sizeof(alarmparam), LONGTXT_ROW_ALARM2_FORMAT,
1856
 
             a.advance,
1857
 
             (a.advanceUnits == advMinutes) ? LONGTXT_ROW_ALARM_MIN_CONST :
1858
 
             (a.advanceUnits == advHours) ? LONGTXT_ROW_ALARM_HOURS_CONST :
1859
 
             (a.advanceUnits == advDays) ? LONGTXT_ROW_ALARM_DAYS_CONST :
1860
 
             LONGTXT_ROW_ALARM_UNKNOWN_CONST);
1861
 
    longtxt_write(out_file, "%s%s",
1862
 
                  LONGTXT_ROW_ALARM1_FORMAT,
1863
 
                  alarmparam);
1864
 
    longtxt_write_str(out_file, "\n");
1865
 
  }
1866
 
 
1867
 
  /* Note */
1868
 
  if(a.note) {
1869
 
    /* Print it this way to properly count lines */
1870
 
    longtxt_write_str(out_file, LONGTXT_ROW_NOTE_FORMAT);
1871
 
    longtxt_write_str(out_file, a.note);
1872
 
    longtxt_write_str(out_file, "\n");
1873
 
  }
1874
 
 
1875
 
  /* Have at least one empty line between rows */
1876
 
  longtxt_write_str(out_file, "\n");
1877
 
 
1878
 
  /* Increase counters */
1879
 
  out_file->num_recs++;
1880
 
  out_file->next_rec++;
1881
 
 
1882
 
  /* Update statistics */
1883
 
  out_file->records_written++;
1884
 
 
1885
 
  /* Debug */
1886
 
  debug_message("Leaving longtxt_write_row\n");
1887
 
}
1888
 
 
1889
 
 
1890
 
 
1891
 
/* For statistics */
1892
 
 
1893
 
/* Show input statistics */
1894
 
void
1895
 
longtxt_show_read_statistics (struct longtxt_file_data * in_file)
1896
 
{
1897
 
 
1898
 
  /* Debug */
1899
 
  debug_message("Entering longtxt_show_read_statistics\n");
1900
 
 
1901
 
  info_message("Input file <%s>, format <%s>:\n",
1902
 
               (in_file->filename) ? in_file->filename : "stdin",
1903
 
               dataformat2txt(DATA_FORMAT_LONGTXT));
1904
 
  info_message("Lines read: %d\n",
1905
 
               in_file->lines_read);
1906
 
  info_message("Records read: %d\n",
1907
 
               in_file->records_read);
1908
 
 
1909
 
  /* Debug */
1910
 
  debug_message("Leaving longtxt_show_read_statistics\n");
1911
 
}
1912
 
 
1913
 
 
1914
 
/* Show output statistics */
1915
 
void
1916
 
longtxt_show_write_statistics (struct longtxt_file_data * out_file)
1917
 
{
1918
 
 
1919
 
  /* Debug */
1920
 
  debug_message("Entering longtxt_show_write_statistics\n");
1921
 
 
1922
 
  info_message("Output file <%s>, format <%s>:\n",
1923
 
               (out_file->filename) ? out_file->filename : "stdout",
1924
 
               dataformat2txt(DATA_FORMAT_LONGTXT));
1925
 
  info_message("Lines written: %d\n",
1926
 
               out_file->lines_written);
1927
 
  info_message("Records written: %d\n",
1928
 
               out_file->records_written);
1929
 
 
1930
 
  /* Debug */
1931
 
  debug_message("Leaving longtxt_show_write_statistics\n");
1932
 
}
1933
 
 
1934
 
 
1935
 
 
1936
 
/* Private functions */
1937
 
 
1938
 
/* Read datebook file header */
1939
 
void
1940
 
longtxt_read_header (struct longtxt_file_data * in_file, struct header_data * header)
1941
 
{
1942
 
  struct DBInfo ip;
1943
 
  struct AppointmentAppInfo aai;
1944
 
  int app_info_size;
1945
 
  void * sort_info;
1946
 
  int sort_info_size;
1947
 
 
1948
 
  int num_read = 0;
1949
 
 
1950
 
  char buffer[0xffff];
1951
 
  char buffer1[0xffff];
1952
 
  char buffer2[0xffff];
1953
 
  char buffer3[0xffff];
1954
 
  char buffer4[0xffff];
1955
 
  char buffer5[0xffff];
1956
 
  char buffer6[0xffff];
1957
 
  char buffer7[0xffff];
1958
 
 
1959
 
  char long_buffer[50];
1960
 
  time_t t;
1961
 
 
1962
 
  int j = 0;
1963
 
 
1964
 
 
1965
 
 
1966
 
  /* Debug */
1967
 
  debug_message("Entering longtxt_read_header\n");
1968
 
 
1969
 
  /* Init data structures */
1970
 
  memset(&ip, 0, sizeof(ip));
1971
 
  memset(&aai, 0, sizeof(aai));
1972
 
 
1973
 
  /* Read general database header data */
1974
 
  do {
1975
 
    /* Skip empty lines */
1976
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
1977
 
    while (buffer[0] == '\n') {
1978
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
1979
 
    }
1980
 
    if (feof(in_file->file))
1981
 
      error_message("Read unexpected end of input file at line %d\n\n",
1982
 
                    in_file->line_no);
1983
 
 
1984
 
    /* Check for UNTIMED_EVENT or APPOINTMENT */
1985
 
    if(!strncmp(buffer,
1986
 
                LONGTXT_ROW_UNTIMED1_FORMAT,
1987
 
                sizeof(LONGTXT_ROW_UNTIMED1_FORMAT) -1)) {
1988
 
      /* Found UNTIMED_EVENT => No header present */
1989
 
      longtxt_pushback_line(buffer, in_file);
1990
 
      break;
1991
 
    }
1992
 
    else if(!strncmp(buffer,
1993
 
                     LONGTXT_ROW_APPOINTMENT1_FORMAT,
1994
 
                     sizeof(LONGTXT_ROW_APPOINTMENT1_FORMAT) -1)) {
1995
 
      /* Found APPOINTMENT => No header present */
1996
 
      longtxt_pushback_line(buffer, in_file);
1997
 
      break;
1998
 
    }
1999
 
 
2000
 
    /* Read database name */
2001
 
    num_read = sscanf (buffer, LONGTXT_HEADER_NAME_FORMAT,
2002
 
                       ip.name);
2003
 
    if (num_read != 1) {
2004
 
      warn_message("Can not read header name from input file line %d\n\n",
2005
 
                   in_file->line_no);
2006
 
      break;
2007
 
    }
2008
 
 
2009
 
 
2010
 
    /* Read database flags */
2011
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
2012
 
    num_read = sscanf (buffer, LONGTXT_HEADER_FLAGS_FORMAT,
2013
 
                       &ip.flags,
2014
 
                       buffer1,
2015
 
                       buffer2,
2016
 
                       buffer3,
2017
 
                       buffer4,
2018
 
                       buffer5,
2019
 
                       buffer6,
2020
 
                       buffer7);
2021
 
    if (num_read <= 0) {
2022
 
      warn_message("Can not read flags from input file line %d\n\n",
2023
 
                   in_file->line_no);
2024
 
      break;
2025
 
    }
2026
 
    if (ip.flags & dlpDBFlagResource) {
2027
 
      warn_message("Input file is not a Datebook file, resource flag is set!\n\n");
2028
 
      break;
2029
 
    }
2030
 
 
2031
 
 
2032
 
    /* Read database misc flags */
2033
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
2034
 
    num_read = sscanf (buffer, LONGTXT_HEADER_MISC_FLAGS_FORMAT,
2035
 
                       &ip.miscFlags);
2036
 
    if (num_read != 1) {
2037
 
      warn_message("Can not read misc flags from input file line %d\n\n",
2038
 
                   in_file->line_no);
2039
 
      break;
2040
 
    }
2041
 
 
2042
 
 
2043
 
    /* Read database type */
2044
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
2045
 
    num_read = sscanf (buffer, LONGTXT_HEADER_TYPE_FORMAT,
2046
 
                       long_buffer);
2047
 
    if (num_read != 1) {
2048
 
      warn_message("Can not read database type from input file line %d\n\n",
2049
 
                   in_file->line_no);
2050
 
      break;
2051
 
    }
2052
 
    ip.type = makelong(long_buffer);
2053
 
 
2054
 
 
2055
 
    /* Read database creator */
2056
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
2057
 
    num_read = sscanf (buffer, LONGTXT_HEADER_CREATOR_FORMAT,
2058
 
                       long_buffer);
2059
 
    if (num_read != 1) {
2060
 
      warn_message("Can not read creator from input file line %d\n\n",
2061
 
                   in_file->line_no);
2062
 
      break;
2063
 
    }
2064
 
    ip.creator = makelong(long_buffer);
2065
 
 
2066
 
 
2067
 
    /* Read database version */
2068
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
2069
 
    num_read = sscanf (buffer, LONGTXT_HEADER_VERSION_FORMAT,
2070
 
                       &ip.version);
2071
 
    if (num_read != 1) {
2072
 
      warn_message("Can not read version from input file line %d\n\n",
2073
 
                   in_file->line_no);
2074
 
      break;
2075
 
    }
2076
 
 
2077
 
 
2078
 
    /* Read database modification number */
2079
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
2080
 
    num_read = sscanf (buffer, LONGTXT_HEADER_MODIFICATION_FORMAT,
2081
 
                       &ip.modnum);
2082
 
    if (num_read != 1) {
2083
 
      warn_message("Can not read modification number from input file line %d\n\n",
2084
 
                   in_file->line_no);
2085
 
      break;
2086
 
    }
2087
 
 
2088
 
 
2089
 
    /* Read database creation time */
2090
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
2091
 
    num_read = sscanf (buffer, LONGTXT_HEADER_CREATE_TIME_FORMAT,
2092
 
                       &buffer1, &buffer2, &buffer3, &buffer4);
2093
 
    if (num_read < 2 || num_read > 4) {
2094
 
      warn_message("Can not read creation time from input file line %d\n\n",
2095
 
                   in_file->line_no);
2096
 
      break;
2097
 
    }
2098
 
    t = read_iso_time_str4n (num_read, buffer1, buffer2, buffer3, buffer4);
2099
 
    if (t == -1)
2100
 
      info_message("Can not parse creation time from input file line %d\n\n",
2101
 
                   in_file->line_no);
2102
 
    ip.createDate = t;
2103
 
 
2104
 
 
2105
 
    /* Read database modification time */
2106
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
2107
 
    num_read = sscanf (buffer, LONGTXT_HEADER_MODIFY_TIME_FORMAT,
2108
 
                       &buffer1, &buffer2, &buffer3, &buffer4);
2109
 
    if (num_read < 2 || num_read > 4) {
2110
 
      warn_message("Can not read modification time from input file line %d\n\n",
2111
 
                   in_file->line_no);
2112
 
      break;
2113
 
    }
2114
 
    t = read_iso_time_str4n (num_read, buffer1, buffer2, buffer3, buffer4);
2115
 
    if (t == -1)
2116
 
      info_message("Can not parse modification time from input file line %d\n\n",
2117
 
                   in_file->line_no);
2118
 
    ip.modifyDate = t;
2119
 
 
2120
 
 
2121
 
    /* Read database backup time */
2122
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
2123
 
    num_read = sscanf (buffer, LONGTXT_HEADER_BACKUP_TIME_FORMAT,
2124
 
                       &buffer1, &buffer2, &buffer3, &buffer4);
2125
 
    if (num_read < 2 || num_read > 4) {
2126
 
      warn_message("Can not read backup time from input file line %d\n\n",
2127
 
                   in_file->line_no);
2128
 
      break;
2129
 
    }
2130
 
    t = read_iso_time_str4n (num_read, buffer1, buffer2, buffer3, buffer4);
2131
 
    if (t == -1)
2132
 
      info_message("Can not parse backup time from input file line %d\n\n",
2133
 
                   in_file->line_no);
2134
 
    ip.backupDate = t;
2135
 
 
2136
 
 
2137
 
    /* Read database index */
2138
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
2139
 
    num_read = sscanf (buffer, LONGTXT_HEADER_INDEX_FORMAT,
2140
 
                       &ip.index);
2141
 
    if (num_read != 1) {
2142
 
      warn_message("Can not read index from input file line %d\n\n",
2143
 
                   in_file->line_no);
2144
 
      break;
2145
 
    }
2146
 
 
2147
 
 
2148
 
 
2149
 
    /* Read datebook application information header data */
2150
 
 
2151
 
    /* Skip empty lines, then check for category header */
2152
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
2153
 
    while (buffer[0] == '\n') {
2154
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
2155
 
    }
2156
 
    if (!strncmp(buffer, LONGTXT_HEADER_NO_APP_INFO,
2157
 
                 sizeof(LONGTXT_HEADER_NO_APP_INFO))) {
2158
 
      /* No application header found */
2159
 
      app_info_size = 0;
2160
 
    }
2161
 
    else {
2162
 
      /* Found application header */
2163
 
      if (strncmp(buffer, LONGTXT_HEADER_CATEGORY_HEADER1_FORMAT,
2164
 
                  sizeof(LONGTXT_HEADER_CATEGORY_HEADER1_FORMAT))) {
2165
 
        warn_message("Can not read category header 1 from input file line %d\n\n",
2166
 
                     in_file->line_no);
2167
 
        break;
2168
 
      }
2169
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
2170
 
      if (strncmp(buffer, LONGTXT_HEADER_CATEGORY_HEADER2_FORMAT,
2171
 
                  sizeof(LONGTXT_HEADER_CATEGORY_HEADER2_FORMAT))) {
2172
 
        warn_message("Can not read category header 2 from input file line %d\n\n",
2173
 
                     in_file->line_no);
2174
 
        break;
2175
 
      }
2176
 
 
2177
 
      /* Read category rows */
2178
 
      for(j=0;j<DATEBOOK_MAX_CATEGORIES;j++) {
2179
 
        longtxt_read_line(buffer, sizeof(buffer), in_file);
2180
 
        num_read = sscanf (buffer, LONGTXT_HEADER_CATEGORY_ROW_FORMAT,
2181
 
                           buffer1,
2182
 
                           &((aai.category).ID[j]),
2183
 
                           buffer2,
2184
 
                           &((aai.category).name[j]));
2185
 
        if (num_read != 4) {
2186
 
          /* Allow category 0 to be without name (Unfiled) */
2187
 
          if (j != 0 || num_read != 3) {
2188
 
            warn_message("Can not read category row %d from input file line %d\n\n",
2189
 
                         j, in_file->line_no);
2190
 
            break;
2191
 
          }
2192
 
        }
2193
 
        if (strncmp(buffer2, LONGTXT_HEADER_RENAMED_YES, sizeof(buffer2)))
2194
 
          (aai.category).renamed[j] = 0;
2195
 
        else
2196
 
          (aai.category).renamed[j] = 1;
2197
 
        if (!strncmp((aai.category).name[j],
2198
 
                     LONGTXT_HEADER_RENAMED_UNUSED,
2199
 
                     sizeof(LONGTXT_HEADER_RENAMED_UNUSED))) {
2200
 
          memset((aai.category).name[j], 0, sizeof((aai.category).name[j]));
2201
 
        }
2202
 
      } /* for all categories */
2203
 
 
2204
 
      /* Skip empty lines, then read last unique category id */
2205
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
2206
 
      while (buffer[0] == '\n') {
2207
 
        longtxt_read_line(buffer, sizeof(buffer), in_file);
2208
 
      }
2209
 
      num_read = sscanf (buffer, LONGTXT_HEADER_LAST_UNIQUE_ID_FORMAT,
2210
 
                         &((aai.category).lastUniqueID));
2211
 
      if (num_read != 1) {
2212
 
        warn_message("Can not read last unique category id from input file line %d\n\n",
2213
 
                     in_file->line_no);
2214
 
        break;
2215
 
      }
2216
 
 
2217
 
 
2218
 
      /* Read start of week */
2219
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
2220
 
      num_read = sscanf (buffer, LONGTXT_HEADER_START_OF_WEEK_FORMAT,
2221
 
                         &aai.startOfWeek);
2222
 
      if (num_read != 1) {
2223
 
        warn_message("Can not read start of Week from input file line %d\n\n",
2224
 
                     in_file->line_no);
2225
 
        break;
2226
 
      }
2227
 
 
2228
 
      /* Set size of application information header data */
2229
 
      app_info_size = sizeof(header->aai);
2230
 
    } /* else (no application information) */
2231
 
 
2232
 
 
2233
 
    /* Read datebook sort information header data */
2234
 
    sort_info = NULL;
2235
 
    sort_info_size = 0;
2236
 
 
2237
 
    /* Skip empty lines, then read 'no sort info'
2238
 
     * TODO: read in sort info according to hex dump written by write_header
2239
 
     */
2240
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
2241
 
    while (buffer[0] == '\n') {
2242
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
2243
 
    }
2244
 
    if (strncmp(buffer, LONGTXT_HEADER_NO_SORT_INFO,
2245
 
                sizeof(LONGTXT_HEADER_NO_SORT_INFO))) {
2246
 
      warn_message("Can not read hint on no sort info from input file line %d\n\n",
2247
 
                   in_file->line_no);
2248
 
      break;
2249
 
    }
2250
 
 
2251
 
 
2252
 
    /* Skip empty lines to find begin of row data */
2253
 
    longtxt_read_line(buffer, sizeof(buffer), in_file);
2254
 
    while (buffer[0] == '\n') {
2255
 
      longtxt_read_line(buffer, sizeof(buffer), in_file);
2256
 
    }
2257
 
 
2258
 
    /* Put last line back, to be read on next read attempt */
2259
 
    longtxt_pushback_line(buffer, in_file);
2260
 
 
2261
 
 
2262
 
    /* Set datebook header data if header has not already been read.
2263
 
     * If header has already been read earlier, then the longtxt read
2264
 
     * header information is ignored - but we are properly positioned
2265
 
     * for reading row data now.
2266
 
     */
2267
 
    if (header->isValid) {
2268
 
      info_message("Skip reading header data, since header has already been read.\n");
2269
 
    }
2270
 
    else {
2271
 
      header->info = ip;
2272
 
      header->aai = aai;
2273
 
      header->app_info_size = app_info_size;
2274
 
      header->sort_info = sort_info;
2275
 
      header->sort_info_size = sort_info_size;
2276
 
      header->isValid = TRUE;
2277
 
    }
2278
 
  } while (FALSE);
2279
 
 
2280
 
  /* Debug */
2281
 
  debug_message("Leaving longtxt_read_header\n");
2282
 
}
2283
 
 
2284
 
 
2285
 
/* Write datebook file header */
2286
 
void
2287
 
longtxt_write_header (struct longtxt_file_data * out_file, struct header_data * header)
2288
 
{
2289
 
  struct DBInfo * ip;
2290
 
  struct AppointmentAppInfo * aai;
2291
 
  void * sort_info;
2292
 
  int sort_info_size;
2293
 
 
2294
 
  char time_buffer[50];
2295
 
 
2296
 
  int j;
2297
 
 
2298
 
 
2299
 
  /* Debug */
2300
 
  debug_message("Entering longtxt_write_header\n");
2301
 
 
2302
 
  if (header->isValid) {
2303
 
    /* Get datebook header data */
2304
 
    ip = &(header->info);
2305
 
    aai = &(header->aai);
2306
 
    sort_info = header->sort_info;
2307
 
    sort_info_size = header->sort_info_size;
2308
 
 
2309
 
 
2310
 
    /* Print database header flags */
2311
 
    longtxt_write(out_file, LONGTXT_HEADER_NAME_FORMAT,
2312
 
                  ip->name);
2313
 
    longtxt_write(out_file, LONGTXT_HEADER_FLAGS_FORMAT, ip->flags,
2314
 
                  (ip->flags & dlpDBFlagResource) ? " RESOURCE" : "",
2315
 
                  (ip->flags & dlpDBFlagReadOnly) ? " READ_ONLY" : "",
2316
 
                  (ip->flags & dlpDBFlagAppInfoDirty) ? " APP-INFO-DIRTY" : "",
2317
 
                  (ip->flags & dlpDBFlagBackup) ? " BACKUP" : "",
2318
 
                  (ip->flags & dlpDBFlagOpen) ? " OPEN" : "",
2319
 
                  (ip->flags & dlpDBFlagNewer) ? " NEWER" : "",
2320
 
                  (ip->flags & dlpDBFlagReset) ? " RESET" : "");
2321
 
    longtxt_write(out_file, LONGTXT_HEADER_MISC_FLAGS_FORMAT,
2322
 
                  ip->miscFlags);
2323
 
    longtxt_write(out_file, LONGTXT_HEADER_TYPE_FORMAT,
2324
 
                  printlong(ip->type));
2325
 
    longtxt_write(out_file, LONGTXT_HEADER_CREATOR_FORMAT,
2326
 
                  printlong(ip->creator));
2327
 
    longtxt_write(out_file, LONGTXT_HEADER_VERSION_FORMAT,
2328
 
                  ip->version);
2329
 
    longtxt_write(out_file, LONGTXT_HEADER_MODIFICATION_FORMAT,
2330
 
                  ip->modnum);
2331
 
 
2332
 
    write_human_full_time_str (ip->createDate, time_buffer, sizeof(time_buffer));
2333
 
    longtxt_write(out_file, LONGTXT_HEADER_CREATE_TIME_FORMAT,
2334
 
                  time_buffer, "", "", "");
2335
 
 
2336
 
    write_human_full_time_str (ip->modifyDate, time_buffer, sizeof(time_buffer));
2337
 
    longtxt_write(out_file, LONGTXT_HEADER_MODIFY_TIME_FORMAT,
2338
 
                  time_buffer, "", "", "");
2339
 
 
2340
 
    write_human_full_time_str (ip->backupDate, time_buffer, sizeof(time_buffer));
2341
 
    longtxt_write(out_file, LONGTXT_HEADER_BACKUP_TIME_FORMAT,
2342
 
                  time_buffer, "", "", "");
2343
 
 
2344
 
    longtxt_write(out_file, LONGTXT_HEADER_INDEX_FORMAT,
2345
 
                  ip->index);
2346
 
    longtxt_write_str(out_file, "\n");
2347
 
 
2348
 
 
2349
 
    /* Print datebook application header */
2350
 
    if (header->app_info_size <= 0) {
2351
 
      longtxt_write_str(out_file, "\n");
2352
 
      longtxt_write_str(out_file, LONGTXT_HEADER_NO_APP_INFO);
2353
 
    }
2354
 
    else {
2355
 
      longtxt_write_str(out_file, "\n");
2356
 
      longtxt_write_str(out_file, LONGTXT_HEADER_CATEGORY_HEADER1_FORMAT);
2357
 
      longtxt_write_str(out_file, LONGTXT_HEADER_CATEGORY_HEADER2_FORMAT);
2358
 
      for(j=0;j<DATEBOOK_MAX_CATEGORIES;j++) {
2359
 
        longtxt_write(out_file, LONGTXT_HEADER_CATEGORY_ROW_FORMAT,
2360
 
                      j,
2361
 
                      (aai->category).ID[j],
2362
 
                      (aai->category).renamed[j]
2363
 
                      ? LONGTXT_HEADER_RENAMED_YES : LONGTXT_HEADER_RENAMED_NO,
2364
 
                      (aai->category).name[j],
2365
 
                      (j>0 && (aai->category).ID[j] == 0)
2366
 
                      ? LONGTXT_HEADER_RENAMED_UNUSED : "");
2367
 
      }
2368
 
      longtxt_write(out_file, LONGTXT_HEADER_LAST_UNIQUE_ID_FORMAT,
2369
 
                    (aai->category).lastUniqueID);
2370
 
      longtxt_write(out_file, LONGTXT_HEADER_START_OF_WEEK_FORMAT,
2371
 
                    aai->startOfWeek);
2372
 
      longtxt_write_str(out_file, "\n");
2373
 
    }
2374
 
 
2375
 
 
2376
 
    /* Print datebook sort header */
2377
 
    if (sort_info_size > 0)
2378
 
      {
2379
 
        /* Does this ever happen for a datebook database?
2380
 
         * At least currently we will not be able to read the hexdump
2381
 
         * back in.
2382
 
         */
2383
 
        longtxt_write(out_file, "sort_info_size %d\n", sort_info_size);
2384
 
        write_dump (out_file->file, sort_info, sort_info_size);
2385
 
        longtxt_write_str(out_file, "\n");
2386
 
      }
2387
 
    else
2388
 
      {
2389
 
        longtxt_write_str(out_file, LONGTXT_HEADER_NO_SORT_INFO);
2390
 
        longtxt_write_str(out_file, "\n");
2391
 
      }
2392
 
    /* Visually separate header from body */
2393
 
    longtxt_write_str(out_file, "\n");
2394
 
  }
2395
 
  else {
2396
 
    debug_message("No valid header present => skip writing header.\n");
2397
 
  }
2398
 
 
2399
 
  /* Debug */
2400
 
  debug_message("Leaving longtxt_write_header\n");
2401
 
}
2402
 
 
2403
 
 
2404
 
 
2405
 
/* For IO */
2406
 
 
2407
 
/* Read one line from input file */
2408
 
void
2409
 
longtxt_read_line (char * buffer, int buffer_size, struct longtxt_file_data * in_file)
2410
 
{
2411
 
 
2412
 
  /* Check for unexpected end of file */
2413
 
  if (feof(in_file->file))
2414
 
    error_message("Unexpected end of input file, line %d\n\n",
2415
 
                  in_file->line_no);
2416
 
 
2417
 
  /* Read one line */
2418
 
  if (in_file->line_buffer != NULL) {
2419
 
    /* Use pushback buffer, if filled */
2420
 
    strncpy(buffer, in_file->line_buffer, buffer_size);
2421
 
    free (in_file->line_buffer);
2422
 
    in_file->line_buffer = NULL;
2423
 
    in_file->line_no++;
2424
 
  }
2425
 
  else {
2426
 
    /* Return empty string if fgets fails */
2427
 
    buffer[0] = '\0';
2428
 
 
2429
 
    /* Read from file */
2430
 
    fgets(buffer, buffer_size, in_file->file);
2431
 
    if (!feof(in_file->file)) {
2432
 
      in_file->line_no++;
2433
 
 
2434
 
      /* Check whether entire line could be read */
2435
 
      if (buffer[strlen(buffer) -1] != '\n')
2436
 
        error_message("Line <%d> in input file <%s> exceeds buffer size\n",
2437
 
                      in_file->line_no,
2438
 
                      (in_file->filename==NULL) ? "stdin" : in_file->filename);
2439
 
    }
2440
 
  }
2441
 
}
2442
 
 
2443
 
 
2444
 
/* Push pack one line into input file */
2445
 
void
2446
 
longtxt_pushback_line (char * buffer, struct longtxt_file_data * in_file)
2447
 
{
2448
 
  /* Pushback line buffer to allow for later re-reading */
2449
 
  in_file->line_buffer = strdup(buffer);
2450
 
  in_file->line_no--;
2451
 
}
2452
 
 
2453
 
 
2454
 
/* Write one single string to output file
2455
 
 *
2456
 
 * Especially useful for printing multi-line text, to properly count
2457
 
 * line numbers
2458
 
 */
2459
 
void
2460
 
longtxt_write_str (struct longtxt_file_data * out_file, const char * out_string)
2461
 
{
2462
 
  char * newline_pos;
2463
 
 
2464
 
 
2465
 
  /* Write text */
2466
 
  fprintf (out_file->file, "%s", out_string);
2467
 
 
2468
 
  /* Count printed lines */
2469
 
  newline_pos = data_index(out_string, '\n');
2470
 
  while (newline_pos != NULL) {
2471
 
    out_file->line_no++;
2472
 
    newline_pos = data_index(newline_pos+1, '\n');
2473
 
  }
2474
 
}
2475
 
 
2476
 
 
2477
 
/* Write to output file */
2478
 
void
2479
 
longtxt_write (struct longtxt_file_data * out_file, const char * format, ...)
2480
 
{
2481
 
  va_list printf_args;
2482
 
  char * newline_pos;
2483
 
 
2484
 
 
2485
 
  /* Get variable arguments */
2486
 
  va_start(printf_args, format);
2487
 
 
2488
 
  /* Write text */
2489
 
  vfprintf (out_file->file, format, printf_args);
2490
 
 
2491
 
  /* No more processing of variable arguments */
2492
 
  va_end(printf_args);
2493
 
 
2494
 
  /* Count printed lines
2495
 
   * (only accurate if newlines can be found in format parameter) */
2496
 
  newline_pos = data_index(format, '\n');
2497
 
  while (newline_pos != NULL) {
2498
 
    out_file->line_no++;
2499
 
    newline_pos = data_index(newline_pos+1, '\n');
2500
 
  }
2501
 
}