Documented the Euro and DM keywords better, in order to support both currencies.
[infodrom/dtaus] / dtaus.c
1 /*
2     dtaus.c - Belegloser Datenträgeraustausch mit einer Bank
3     Copyright (c) 1996,8,2001,2  Martin Schulze <joey@infodrom.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
18
19     $Id$
20  */
21
22 #include "dtaus.h"
23 #include "bigint.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <time.h>
29 #include <malloc.h>
30
31 #define DEFAULT_EURO
32 #ifndef DEFAULT_EURO
33 int use_euro = 0;
34 #else
35 int use_euro = 1;
36 #endif
37
38 /*
39  *  First: Some control structures
40  */
41
42 typedef struct
43 {
44   char *name;
45   unsigned short int pos;
46   unsigned short int len;
47   int type;
48 } dtaus_record;
49
50 #define REC_A   1
51 #define REC_C   2
52 #define REC_E   3
53
54 #define REQ     1
55 #define OPT     2
56 #define IGN     3
57
58 dtaus_record recA[] = {
59   {"Art", 5, 2, REQ},
60   {"Name", 23, 27, REQ},
61   {"Konto", 60, 10, REQ},
62   {"BLZ", 7, 8, REQ},
63   {"Referenz", 70, 10, OPT},
64   {"Datum", 50, 6, IGN},
65   {"Ausfuehrung", 95, 8, OPT},
66   {"Currency", 127, 1, OPT},
67   {"Euro", 127, 1, OPT},
68   {"DM", 127, 1, OPT},
69   {NULL, 0, 0}
70 };
71
72 #define A_TRANS 0
73 #define A_NAME  1
74 #define A_KTO   2
75 #define A_BLZ   3
76 #define A_REF   4
77 #define A_DATE  5
78 #define A_TODO  6
79 #define A_CURR  7
80 #define A_EURO  8
81 #define A_DM    9
82 #define A_LEN   10
83 #define A_LOOP  7
84
85 dtaus_record recC[] = {
86   {"Name", 93, 27, REQ},
87   {"Konto", 21, 10, REQ},
88   {"BLZ", 13, 8, REQ},
89   {"Transaktion", 44, 5, REQ},
90 #ifndef DEFAULT_EURO
91   {"Betrag", 50, 11, REQ},
92 #else
93   {"Betrag", 79, 11, REQ},
94 #endif
95   {"Zweck", 155, 27, REQ},
96   {"myName", 128, 27, OPT},
97   {"myKonto", 69, 10, OPT},
98   {"myBLZ", 61, 8, OPT},
99   {"Text", 187, 29, OPT},
100   {"Extension", 216, 29, OPT},
101   {"Currency", 182, 1, IGN},
102 #ifndef DEFAULT_EURO
103   {"Betrag-Euro", 79, 11, IGN},
104 #else
105   {"Betrag-DM", 50, 11, IGN},
106 #endif
107   {NULL, 0, 0}
108 };
109
110 #define C_NAME  0
111 #define C_KTO   1
112 #define C_BLZ   2
113 #define C_TRANS 3
114 #define C_VAL   4
115 #define C_ZWECK 5
116 #define C_MYNAM 6
117 #define C_MYKTO 7
118 #define C_MYBLZ 8
119 #define C_TEXT  9
120 #define C_EXT  10
121 #define C_EURO 11
122 #ifndef DEFAULT_EURO
123 #define C_EUR  12
124 #else
125 #define C_DM   12
126 #endif
127 #define C_LEN  13
128 #define C_LOOP 11
129
130 #define MAX_TEXT 14
131
132 dtaus_record recE[] = {
133   {"Anzahl", 10, 7, IGN},
134 #ifndef DEFAULT_EURO
135   {"Summe", 17, 13, IGN},
136 #else
137   {"Summe", 64, 13, IGN},
138 #endif
139   {"Kontos", 30, 17, IGN},
140   {"BLZs", 47, 17, IGN},
141 #ifndef DEFAULT_EURO
142   {"Summe-Euro", 64, 13, IGN},
143 #else
144   {"Summe-DM", 17, 13, IGN},
145 #endif
146   {NULL, 0, 0}
147 };
148
149 #define E_COUNT 0
150 #define E_VAL   1
151 #define E_KTO   2
152 #define E_BLZ   3
153 #ifndef DEFAULT_EURO
154 #define E_EUR   4
155 #else
156 #define E_DM    4
157 #endif
158 #define E_LEN   5
159
160 /*
161  *  Second: Some low level routines
162  */
163
164 size_t dtaus_nextrec (void **buf, FILE *f)
165 {
166   memset (buf, 0, 128);
167   return fread(buf, 128, 1, f);
168 }
169
170 char *upcase(char *s)
171 {
172   static char x[100];
173   static char *xp;
174   char *cp;
175
176   for (cp=s,xp=x; *cp; cp++,xp++) {
177     if (strchr(" 0123456789.,&-/+*$%ABCDEFGHIJKLMNOPQRSTUVWXYZ",*cp)) {
178         *xp = *cp;
179     } else if (strchr("abcdefghijklmnopqrstuvwxyz",*cp)) {
180       *xp = toupper(*cp);
181     } else if (strchr ("üÜäÄöÖß", *cp)) {
182       switch (*cp) {
183       case 'ü': *(xp++) = 'U'; *xp='E'; break;
184       case 'Ü': *(xp++) = 'U'; *xp='E'; break;
185       case 'ä': *(xp++) = 'A'; *xp='E'; break;
186       case 'Ä': *(xp++) = 'A'; *xp='E'; break;
187       case 'ö': *(xp++) = 'O'; *xp='E'; break;
188       case 'Ö': *(xp++) = 'O'; *xp='E'; break;
189       case 'ß': *(xp++) = 'S'; *xp='S'; break;
190       }
191     } else
192       /*
193        * Filter out all other characters since credit institutes won't
194        * accept the file otherwise.
195        */
196       *xp = ' ';
197   }
198   *xp = '\0';
199
200   return x;
201 }
202
203 char *downcase(char *s)
204 {
205   static char x[100];
206   char *cp;
207
208   memset (x, 0, sizeof (x));
209   strncpy (x, s, 99);
210   
211   for (cp=x;*cp;cp++)
212     if (isupper(*cp))
213       *cp = tolower(*cp);
214   return x;
215 }
216
217 char *strip_spaces (char *s)
218 {
219   int i;
220   char *p;
221
222   for (i=strlen(s);(s[i-1] == ' '||s[i-1] == '\t')&&i>0; i--)
223     s[i-1] = '\0';
224   for (p=s; *p==' '; p++);
225   return p;
226 }
227
228 char *strip_zeros (char *s)
229 {
230   char *p;
231
232   for (p=s; *p=='0'; p++);
233   return p;
234 }
235
236 char *strip_nondigits (char *s)
237 {
238   char *p;
239   char *x;
240
241   for (x=s,p=s;*x;x++)
242     if (isdigit (*x))
243       *(p++) = *x;
244   *(p++) = '\0';
245
246   return s;
247 }
248
249 char dtaus_char (void *buf, unsigned int pos)
250 {
251   static char res;
252   char *bufp = (char *)buf;
253
254   bufp+=pos;
255   memcpy(&res, bufp, 1);
256   return res;
257 }
258
259 char *string2real(char *s)
260 {
261   static char res[20];
262   char *cp = s;
263
264   cp+=strlen(s)-2;
265   strncpy(res, s, strlen(s)-2);
266   res[strlen(s)-2] = '.';
267   res[strlen(s)-1] = s[strlen(s)-2];
268   res[strlen(s)] = s[strlen(s)-1];
269   return res;
270 }
271
272 char *real2string(char *s)
273 {
274   static char res[20];
275   char *cp;
276
277   strcpy(res, s);
278   for (cp=res; *cp&&!(*cp == ',')&&!(*cp == '.');cp++);
279   *(cp++) = *(cp+1);
280   *(cp++) = *(cp+1);
281   *cp = '\0';
282   return res;
283 }
284
285 char *string2trans (char *s)
286 {
287   static char res[30];
288
289   res[0] = '\0';
290   if (!strcmp(s, "04000"))
291     sprintf (res, "Abbuchung");
292   else if (!strcmp(s, "05000"))
293     sprintf (res, "Einzug");
294   else if (!strcmp(s, "05005"))
295     sprintf (res, "E-Cash");
296   else if (!strcmp(s, "05006"))
297     sprintf (res, "E-Cash-A");
298   else if (!strcmp(s, "51000"))
299     sprintf (res, "Gutschrift");
300   else if (!strcmp(s, "53000"))
301     sprintf (res, "Lohn");
302   else if (!strncmp(s, "5400", 4))
303     sprintf (res, "Vermögen");
304   /*  else if (!strcmp(s, "56000"))
305     sprintf (res, ""); / * Überweisung öffentlicher Kassen */
306   return res;
307 }
308
309 char *trans2string (char *s)
310 {
311   static char res[30];
312
313   res[0] = '\0';
314   if (!strcmp(s, "Abbuchung"))
315     sprintf (res, "04000");
316   else if (!strcmp(s, "Einzug"))
317     sprintf (res, "05000");
318   else if (!strcmp(s, "E-Cash"))
319     sprintf (res, "05005");
320   else if (!strcmp(s, "E-Cash-A"))
321     sprintf (res, "05006");
322   else if (!strcmp(s, "Gutschrift"))
323     sprintf (res, "51000");
324   else if (!strcmp(s, "Lohn"))
325     sprintf (res, "53000");
326   else if (!strncmp(s, "Vermögen", 4))
327     sprintf (res, "5400");
328   /*  else if (!strcmp(s, ""))
329     sprintf (res, "56000"); / * Überweisung öffentlicher Kassen */
330   return res;
331 }
332
333 char *string2ext (char *s)
334 {
335   static char res[30];
336
337   res[0] = '\0';
338   if (!strcmp(s, "01"))
339     sprintf (res, "Kunde");
340   else if (!strcmp(s, "02"))
341     sprintf (res, "Text");
342   else if (!strcmp(s, "03"))
343     sprintf (res, "Auftraggeber");
344   return res;
345 }
346
347 char *ext2string (char *s)
348 {
349   static char res[3];
350
351   res[0] = '\0';
352   if (!strcmp(s, "Kunde"))
353     sprintf (res, "01");
354   else if (!strcmp(s, "Text"))
355     sprintf (res, "02");
356   else if (!strcmp(s, "Auftraggeber"))
357     sprintf (res, "03");
358   return res;
359 }
360     
361 unsigned long int dtaus_int(void *buf, unsigned int pos, unsigned int len)
362 {
363   char tmp[30];
364   char *bufp = (char *)buf;
365   static unsigned long int res;
366
367   bufp+=pos;
368   memcpy(tmp, bufp, len);
369   tmp[len] = '\0';
370   sscanf(tmp, "%lu", &res);
371   return res;
372 }
373
374 /*
375  * returns the first word in this line, returns it and shortens the
376  * line.
377  */
378 char *extract_ident (char *line)
379 {
380   char *c, *x, *y;
381   static char word[30];
382
383   if (strlen(line) > 0) {
384     x = strchr (line, ' ');
385     y = strchr (line, '\t');
386
387     if (!x && !y) {
388         strncpy(word, line, 29);
389         line[0] = '\0';
390         return word;
391     }
392
393     /* Check which index returns the lower value, and check if the
394        value is non-NULL */
395     if ((c = (x && x<y)?x:(y?y:x))) { 
396       strncpy(word, line, c - line);
397       word[c-line] = '\0';
398       for (;*c == '\t' || *c == ' '; c++);
399       for (x=line; *c; c++,x++)
400         *x = *c;
401       *x = '\0';
402       strcpy(word, downcase(word));
403       return word;
404     }
405     return NULL;
406   }
407   return line;
408 }
409
410 /*
411  * Pads a string with zero's on the left side.
412  */
413 char *padzeroclip (char *s, int len)
414 {
415   char *p, *q;
416
417   if (strlen(s) == len) return s;
418   if (strlen(s) > len) {
419       q=s+len;
420       *(q--) = '\0';
421       return s;
422   }
423
424   q=s+len;
425   *(q--) = '\0';
426   for (p=s+strlen(s)-1;p>=s;p--)
427     *(q--)=*p;
428   for (;q>=s;) *(q--)='0';
429   return s;
430 }
431
432 int rec_index(char *ident, int type)
433 {
434   int i;
435   dtaus_record *rec = NULL;
436
437   switch (type) {
438   case REC_A:   rec = recA; break;
439   case REC_C:   rec = recC; break;
440   case REC_E:   rec = recE; break;
441   }
442
443   for (i=0; (rec[i].name); i++) {
444     if (!strcmp(ident, downcase(rec[i].name)))
445       return i;
446   }
447
448   return -1;
449 }
450
451 size_t control_nextline (void **buf, int len, FILE *f)
452 {
453   char line[100];
454   char tmp[100];
455   char *cp;
456   int i;
457
458   memset (line, 0, sizeof(line));
459   memset (buf, 0, len);
460   cp = line;
461
462   while (!strlen(line) && (cp = fgets(line, 100, f))) {
463     if (strlen(line)) {
464       if (line[0] != '#') {
465         if (line[strlen(line)-1] != '\n') { 
466           strcpy(tmp, line);
467           while (tmp[strlen(tmp)-1] != '\n' && (cp = fgets(tmp, 100, f)));
468         } else
469           line[strlen(line)-1] = '\0';
470         if (line[strlen(line)-1] == '\r')
471           line[strlen(line)-1] = '\0';
472         for (i=strlen(line);(line[i-1] == ' '||line[i-1] == '\t')&&i>0; i--)
473           line[i-1] = '\0';
474         if (line[0] == '#')
475           line[0] = '\0';
476       } else
477         line[0] = '\0';
478     }
479   }
480   for (cp=line; *cp==' '; cp++);
481
482   if (strlen(cp)) {
483     memcpy(buf, cp, strlen(cp));
484     return 1;
485   } else
486     return 0;
487 }
488
489 char *get_date()
490 {
491   static char res[10];
492   time_t timer;
493   struct tm *loctime;
494
495   timer = time ( NULL );
496   loctime = localtime(&timer);
497   sprintf(res, "%02d.%02d.%02d", loctime->tm_mday, loctime->tm_mon+1, loctime->tm_year % 100);
498   return res;
499 }
500
501 /*
502  *  Prepare a record A according to the specs.
503  *  See dtaus.txt for explanation
504  */
505 void dtaus_prepareA (char *buf)
506 {
507   int i;
508   time_t timer;
509   struct tm *loctime;
510   char tmp[10];
511
512   memset (buf, 0, 129);
513   timer = time ( NULL );
514   loctime = localtime(&timer);
515
516   buf[0] = '0';
517   buf[1] = '1';
518   buf[2] = '2';
519   buf[3] = '8';
520   buf[4] = 'A';
521   for (i=15;i<15+8; i++) buf[i] = '0';          /* A5 */
522   sprintf(tmp, "%02d%02d%02d", loctime->tm_mday, loctime->tm_mon+1, loctime->tm_year % 100);
523   for (i=0; i<6; i++) buf[50+i] = tmp[i];       /* A7 (Date) */
524   for (i=56;i<56+4; i++) buf[i] = ' ';          /* A8 */
525   for (i=70;i<70+10; i++) buf[i] = '0';         /* A10 */
526   for (i=80;i<80+48; i++) buf[i] = ' ';         /* A11 */
527   if (use_euro)
528     buf[recA[A_CURR].pos] = '1';                                /* A12 (Currency) */
529   else
530     buf[recA[A_CURR].pos] = ' ';                                /* A12 (Currency) */
531 }
532
533 /*
534  *  Prepare a record C according to the specs.
535  *  See dtaus.txt for explanation
536  */
537 void dtaus_prepareC (char *buf, int normaltext, int maxtext)
538 {
539   int i;
540   int appendix = 0;
541
542   memset (buf, 0, 257);
543
544   if (normaltext)
545     appendix = 1;
546   appendix += maxtext;
547   i = 187 + (appendix * 29);
548
549   /* Bail out if the number is too large, shouldn't be possible though */
550   if (i >= 1000)
551     exit (1);
552
553   buf[0] = (i/1000)+48;i-=(i/1000)*100;
554   buf[1] = (i/100)+48;i-=(i/100)*100;
555   buf[2] = (i/10)+48;i-=(i/10)*10;
556   buf[3] = i+48;
557   buf[4] = 'C';
558
559   for (i=31;i<31+13; i++) buf[i] = '0';         /* C6 */
560   buf[49] = ' ';                                /* C8 */
561   for (i=50;i<50+11; i++) buf[i] = '0';         /* C9 (Betrag) */
562   for (i=79;i<79+11; i++) buf[i] = '0';         /* C12 (Betrag Euro) */
563   for (i=90;i<90+3; i++) buf[i] = ' ';          /* C13 */
564   for (i=93;i<90+27; i++) buf[i] = ' ';         /* C14a (Kunde) */
565   for (i=120;i<120+8; i++) buf[i] = ' ';        /* C14b */
566   if (use_euro)
567     buf[recC[C_EURO].pos] = '1';                                /* C17a (Currency) */
568   else
569     buf[recC[C_EURO].pos] = ' ';                                /* C17a (Currency) */
570   for (i=183;i<183+2; i++) buf[i] = ' ';        /* C17b */
571   for (i=187;i<187+(29*2); i++) buf[i] = ' ';   /* C19-C22 (misc text) */
572   for (i=245;i<245+11; i++) buf[i] = ' ';       /* C23 */
573
574   buf[185+0] = (appendix/10)+48;appendix-=(appendix/10)*10;
575   buf[185+1] = appendix+48;
576 }
577
578 /*
579  *  Prepare a record E according to the specs.
580  *  See dtaus.txt for explanation
581  */
582 void dtaus_prepareE (char *buf)
583 {
584   int i;
585
586   memset (buf, 0, 129);
587   buf[0] = '0';
588   buf[1] = '1';
589   buf[2] = '2';
590   buf[3] = '8';
591   buf[4] = 'E';
592   for (i=5;i<5+5; i++) buf[i] = ' ';    /* E3 */
593   for (i=17;i<17+13; i++) buf[i] = '0'; /* E8 (Check Betrag) */
594   for (i=64;i<64+13; i++) buf[i] = '0'; /* E8 (Check Euro) */
595   for (i=77;i<77+51; i++) buf[i] = ' '; /* E9 */
596 }
597
598 int dtaus_writeA(FILE *f, char **values)
599 {
600   char buf[129];
601   char tmp[30];
602   int i;
603   
604   for (i=0; (recA[i].name); i++)
605     if ((recA[i].type == REQ) && !values[i]) {
606       fprintf (stderr, "Anfangsdatensatz ist nicht vollständig, kein %s.\n", recA[i].name);
607       return 0;
608     }
609   if (!(((values[A_TRANS][0] == 'L')||(values[A_TRANS][0] == 'G'))
610         &&((values[A_TRANS][1] == 'B')||(values[A_TRANS][1] == 'K')))) {
611     fprintf (stderr, "Ungültiger Typ, nur LK, GK, LB oder GB erlaubt.\n");
612     return 0;
613   }
614
615   i=A_NAME;if (values[i] && strlen(values[i]) > recA[i].len)
616     values[i][recA[i].len] = '\0';
617
618   dtaus_prepareA(buf);
619   buf[5] = values[A_TRANS][0];
620   buf[6] = values[A_TRANS][1];
621   sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[A_BLZ]),recA[A_BLZ].len));
622   for (i=0; i<recA[A_BLZ].len; i++) buf[recA[A_BLZ].pos+i] = tmp[i];
623   sprintf (tmp, "%-27.27s", upcase(values[A_NAME]));
624   for (i=0; i<27; i++) buf[recA[A_NAME].pos+i] = tmp[i];
625   if (values[A_TODO]) {
626     sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[A_TODO]),recA[A_TODO].len));
627     for (i=0; i<recA[A_TODO].len; i++) buf[recA[A_TODO].pos+i] = tmp[i];
628   }
629   sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[A_KTO]),recA[A_KTO].len));
630   for (i=0; i<recA[A_KTO].len; i++) buf[recA[A_KTO].pos+i] = tmp[i];
631
632   fputs(buf, f);
633   return 1;
634 }
635
636 int dtaus_writeC(FILE *f, char **valuesA, char **values, char **text)
637 {
638   char buf[257];
639   char appendix[129];
640   char tmp[30];
641   int i, k;
642   int maxtext = 0;
643   int fieldnr;
644
645   /* Just count */
646   if (text) for (maxtext=0;text[maxtext];maxtext++);
647
648 #if DEBUG
649   for (i=0; (recC[i].name); i++)
650     if (values[i])
651       printf ("%s: %s\n", recC[i].name, values[i]);
652 #endif
653
654   for (i=0; (recC[i].name); i++)
655     if ((recC[i].type == REQ) && !values[i]) {
656       fprintf (stderr, "Datensatz ist nicht vollständig, kein %s.\n", recC[i].name);
657       return 0;
658     }
659   sprintf (tmp, "%s", trans2string(values[C_TRANS]));
660   if (!strlen(tmp)) {
661     fprintf (stderr, "Ungültiger Typ, nur Abbuchung, Einzug, E-Cash, E-Cash-A, Gutschrift und Lohn erlaubt.\n");
662     return 0;
663   }
664
665   i=C_TEXT;if (values[i] && strlen(values[i]) > recC[i].len)
666     values[i][recC[i].len-2] = '\0';
667   i=C_ZWECK;if (values[i] && strlen(values[i]) > recC[i].len)
668     values[i][recC[i].len] = '\0';
669   i=C_MYNAM;if (values[i] && strlen(values[i]) > recC[i].len)
670     values[i][recC[i].len] = '\0';
671   i=C_TEXT;if (values[i] && strlen(values[i]) > recC[i].len)
672     values[i][recC[i].len] = '\0';
673
674   dtaus_prepareC (buf, values[C_TEXT] != NULL, maxtext);
675   for (i=0; i<5; i++) buf[recC[C_TRANS].pos+i] = tmp[i];
676   if (values[C_MYBLZ])
677     sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[C_MYBLZ]),8));
678   else
679     sprintf (tmp, "%s", padzeroclip (strip_nondigits (valuesA[A_BLZ]),8));
680   for (i=0; i<recC[C_MYBLZ].len; i++) buf[5+i] = tmp[i];
681   for (i=0; i<recC[C_MYBLZ].len; i++) buf[recC[C_MYBLZ].pos+i] = tmp[i];
682   sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[C_BLZ]),8));
683   for (i=0; i<recC[C_BLZ].len; i++) buf[recC[C_BLZ].pos+i] = tmp[i];
684   sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[C_KTO]),10));
685   for (i=0; i<recC[C_KTO].len; i++) buf[recC[C_KTO].pos+i] = tmp[i];
686   sprintf (tmp, "%s", padzeroclip (real2string(values[C_VAL]),11));
687 #ifndef DEFAULT_EURO
688   if (!use_euro)
689     for (i=0; i<recC[C_VAL].len; i++) buf[recC[C_VAL].pos+i] = tmp[i];
690   else
691     for (i=0; i<recC[C_EUR].len; i++) buf[recC[C_EUR].pos+i] = tmp[i];
692 #else
693   if (use_euro)
694     for (i=0; i<recC[C_VAL].len; i++) buf[recC[C_VAL].pos+i] = tmp[i];
695   else
696     for (i=0; i<recC[C_DM].len; i++) buf[recC[C_DM].pos+i] = tmp[i];
697 #endif
698   if (values[C_MYKTO])
699     sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[C_MYKTO]),10));
700   else
701     sprintf (tmp, "%s", padzeroclip (strip_nondigits (valuesA[A_KTO]),10));
702   for (i=0; i<recC[C_MYKTO].len; i++) buf[recC[C_MYKTO].pos+i] = tmp[i];
703   sprintf (tmp, "%-27.27s", upcase(values[C_NAME]));
704   for (i=0; i<recC[C_NAME].len; i++) buf[recC[C_NAME].pos+i] = tmp[i];
705   if (values[C_MYNAM])
706     sprintf (tmp, "%-27.27s", upcase(values[C_MYNAM]));
707   else
708     sprintf (tmp, "%-27.27s", upcase(valuesA[A_NAME]));
709   for (i=0; i<recC[C_MYNAM].len; i++) buf[recC[C_MYNAM].pos+i] = tmp[i];
710   sprintf (tmp, "%-27.27s", upcase(values[C_ZWECK]));
711   for (i=0; i<recC[C_ZWECK].len; i++) buf[recC[C_ZWECK].pos+i] = tmp[i];
712
713   if (values[C_TEXT]) {
714     buf[recC[C_TEXT].pos+0] = '0';
715     buf[recC[C_TEXT].pos+1] = '2';
716     sprintf (tmp, "%-27.27s", upcase(values[C_TEXT]));
717     for (i=0; i<recC[C_TEXT].len-2; i++) buf[recC[C_TEXT].pos+2+i] = tmp[i];
718   }
719
720   if (text) {
721     buf[recC[C_EXT].pos+0] = '0';
722     buf[recC[C_EXT].pos+1] = '2';
723     sprintf (tmp, "%-27.27s", upcase(text[0]));
724     for (i=0; i<recC[C_EXT].len-2; i++) buf[recC[C_EXT].pos+2+i] = tmp[i];
725   }
726
727   fputs(buf, f);
728
729   if (text && maxtext > 1) {
730     fieldnr=1;
731     while (fieldnr<maxtext) {
732       memset (appendix, ' ', 128);
733       appendix[128] = '\0';
734       for (k=0; k<4 && (fieldnr+k)<maxtext; k++) {
735         sprintf (tmp, "%-27.27s", upcase(text[fieldnr+k]));
736         appendix[k*29] = '0';
737         appendix[(k*29)+1] = '2';
738         for (i=0; i<recC[C_TEXT].len-2; i++) appendix[(k*29)+2+i] = tmp[i];
739       }
740       fputs(appendix, f);
741       fieldnr += k;
742     }
743   }
744
745   return 1;
746 }
747
748 int dtaus_writeE(FILE *f, int count, bigint sum, bigint blz, bigint kto)
749 {
750   char buf[129];
751   char tmp[30];
752   int i;
753   
754   dtaus_prepareE(buf);
755
756   sprintf (tmp, "%07d", count);
757   for (i=0; i<recE[E_COUNT].len; i++) buf[recE[E_COUNT].pos+i] = tmp[i];
758   bigint_sprintf (tmp, "%s", sum);
759   padzeroclip (tmp,13);
760 #ifndef DEFAULT_EURO
761   if (!use_euro)
762     for (i=0; i<recE[E_VAL].len; i++) buf[recE[E_VAL].pos+i] = tmp[i];
763   else
764     for (i=0; i<recE[E_EUR].len; i++) buf[recE[E_EUR].pos+i] = tmp[i];
765 #else
766   if (use_euro)
767     for (i=0; i<recE[E_VAL].len; i++) buf[recE[E_VAL].pos+i] = tmp[i];
768   else
769     for (i=0; i<recE[E_DM].len; i++) buf[recE[E_DM].pos+i] = tmp[i];
770 #endif
771   bigint_sprintf (tmp, "%s", kto);
772   padzeroclip (tmp,17);
773   for (i=0; i<recE[E_KTO].len; i++) buf[recE[E_KTO].pos+i] = tmp[i];
774   bigint_sprintf (tmp, "%s", blz);
775   padzeroclip (tmp,17);
776   for (i=0; i<recE[E_BLZ].len; i++) buf[recE[E_BLZ].pos+i] = tmp[i];
777
778   fputs(buf, f);
779   return 1;
780 }
781
782 void printctln(FILE *f, char *field, char *value)
783 {
784   if (strlen(field) && strlen(value))
785     fprintf(f, "  %s\t%s\n", field, value);
786 }
787
788 /*
789  * one date line, format it properly
790  */
791 void printctlndate(FILE *f, char *field, char *value)
792 {
793   char mydate[11];
794   int i;
795
796   if (!strlen(field) || !strlen(value))
797     return;
798
799   for (i=0;isspace (value[i]) && i<= strlen (value); i++);
800   if (i == strlen (value))
801     return;
802
803   memset (mydate, 0, sizeof (mydate));
804   if (strlen (value) == 6) {
805     mydate[0] = value[0];
806     mydate[1] = value[1];
807     mydate[2] = '.';
808     mydate[3] = value[2];
809     mydate[4] = value[3];
810     mydate[5] = '.';
811     mydate[6] = value[4];
812     mydate[7] = value[5];
813     fprintf(f, "  %s\t%s\n", field, mydate);
814   } else if (strlen (value) == 8) {
815     mydate[0] = value[0];
816     mydate[1] = value[1];
817     mydate[2] = '.';
818     mydate[3] = value[2];
819     mydate[4] = value[3];
820     mydate[5] = '.';
821     mydate[6] = value[4];
822     mydate[7] = value[5];
823     mydate[8] = value[6];
824     mydate[9] = value[7];
825     fprintf(f, "  %s\t%s\n", field, mydate);
826   } else {
827     fprintf (stderr, "Broken date field: %s\n", value);
828     fprintf(f, "  %s\t%s\n", field, value);
829   }
830 }
831
832
833 /*
834  *  Third: Some high level routines
835  */
836
837 void dtaus2control (char *cdtaus, char *ccontrol)
838 {
839   FILE *fdtaus, *fcontrol;
840   char *buf;
841   char *bufp;
842   char tmp[30];
843   char x[30];
844   int index;
845   int extC;
846   div_t res;
847
848   if (!cdtaus) {
849     if (!(fdtaus = fopen("DTAUS0.TXT", "r")))
850       if (!(fdtaus = fopen("dtaus0.txt", "r")))
851         return;
852   } else {
853     if (!strcmp (cdtaus, "-"))
854       fdtaus = stdin;
855     else
856       if (!(fdtaus = fopen(cdtaus, "r")))
857         return;
858   }
859   if (!ccontrol) 
860     fcontrol = stdout;
861   else
862     if (!strcmp (ccontrol, "-"))
863       fcontrol = stdout;
864     else
865       if (!(fcontrol = fopen(ccontrol, "w")))
866         return;
867   if (!(buf = (char *)malloc (512)))
868     return;
869
870   /* 
871    * Record A lesen
872    */
873   if (dtaus_nextrec(buf, fdtaus) == 1) {
874     if (dtaus_char(buf,4) == 'A') {
875       fprintf(fcontrol, "BEGIN {\n");
876       bufp = buf;
877
878       for (index=A_TRANS; index < A_LOOP; index++) {
879         bufp = buf + recA[index].pos;
880         memcpy(tmp, bufp, recA[index].len); tmp[recA[index].len] = '\0';
881         if (index == A_DATE || index == A_TODO)
882           printctlndate(fcontrol, recA[index].name, tmp);
883         else
884           printctln(fcontrol, recA[index].name, strip_zeros(strip_spaces(tmp)));
885       }
886
887       bufp = buf + recA[A_CURR].pos;
888       if (*bufp == '1') {
889         use_euro = 1;
890         fprintf(fcontrol, "  Euro\n");
891       } else {
892         use_euro = 0;
893         fprintf(fcontrol, "  DM\n");
894       }
895
896       fprintf(fcontrol, "}\n\n");
897     } else {
898       fprintf (stderr, "Datei fängt nicht mit dem Anfangsdatensatz an.\n");
899       return;
900     }
901   } else {
902     fprintf (stderr, "Der Anfangsdatensatz ist kaputt.\n");
903     return;
904   }
905
906   /*
907    * Record C lesen
908    */
909   if (dtaus_nextrec(buf, fdtaus) == 1) {
910     while (dtaus_char(buf,4) == 'C') {
911       bufp = buf + 128;
912       if (dtaus_nextrec(bufp, fdtaus) != 1) {
913         fprintf (stderr, "Der zweite Teil der Transaktion ist kaputt.\n");
914         return;
915       } else {
916         fprintf(fcontrol, "{\n");
917
918         for (index=C_NAME; index < C_LOOP; index++) {
919 #ifndef DEFAULT_EURO
920           if (use_euro && index == C_VAL)
921             index = C_EUR;
922 #else
923           if (!use_euro && index == C_VAL)
924             index = C_DM;
925 #endif
926           bufp = buf + recC[index].pos;
927           memcpy(tmp, bufp, recC[index].len); tmp[recC[index].len] = '\0';
928
929           /*
930            * C_EUR and C_DM are outside of the loop, can only be
931            * selected for the non-default currency, but the value
932            * should be stored in the normal record field.
933            */
934 #ifndef DEFAULT_EURO
935           if (index == C_EUR)
936 #else
937           if (index == C_DM)
938 #endif
939             printctln(fcontrol, recC[C_VAL].name, strip_zeros(string2real(tmp)));
940           else if (index == C_VAL)
941             printctln(fcontrol, recC[index].name, strip_zeros(string2real(tmp)));
942           else if (index == C_TRANS)
943             printctln(fcontrol, recC[index].name, strip_zeros(string2trans(tmp)));
944           else
945             printctln(fcontrol, recC[index].name, strip_zeros(strip_spaces(tmp)));
946 #ifndef DEFAULT_EURO
947           if (use_euro && index == C_EUR)
948             index = C_VAL;
949 #else
950           if (!use_euro && index == C_DM)
951             index = C_VAL;
952 #endif
953         }
954
955         for (index=C_TEXT; index <= C_EXT; index++) {
956           if (!(dtaus_char(buf,recC[index].pos) == ' ')) {
957             bufp = buf + recC[index].pos;
958             memcpy(x, bufp, 2); tmp[2] = '\0'; bufp+=2;
959             memcpy(tmp, bufp, recC[index].len-2); tmp[recC[index].len-2] = '\0';
960             printctln(fcontrol, string2ext(x), strip_spaces(tmp));
961           }
962         }
963
964         /* Number of extension records for this C record */
965         extC = dtaus_int(buf, 185, 2);
966         extC -= 2;
967         if (extC > 0) {
968           res = div (extC, 4);
969           extC = res.quot;
970           if (res.rem) extC++;
971         }
972       }
973       if (dtaus_nextrec(buf, fdtaus) != 1)
974         memset (buf, 0, sizeof(buf));
975
976       /*
977        * Are there extension records that we have to check?
978        *
979        * 2nd half of the AND is wrong, but since dtaus < 0.5 wrote 01
980        *     instead of 00 we should let it in so it can read its own
981        *     old files...  *sigh*
982        */
983       while (extC > 0 && dtaus_char(buf,4) != 'C' && dtaus_char(buf,4) != 'E') {
984         for (index=0; index < 4; index++) {
985           if ((dtaus_char(buf,index*29) != ' ')) {
986             bufp = buf + index*29;
987             memcpy(x, bufp, 2); tmp[2] = '\0'; bufp+=2;
988             memcpy(tmp, bufp, recC[C_TEXT].len-2); tmp[recC[C_TEXT].len-2] = '\0';
989             printctln(fcontrol, string2ext(x), strip_spaces(tmp));
990           }
991         }
992         if (dtaus_nextrec(buf, fdtaus) != 1)
993           memset (buf, 0, sizeof(buf));
994         extC--;
995       }
996       fprintf(fcontrol, "}\n");
997     }
998   }
999
1000   /*
1001    * Record E lesen
1002    *   (gelesen ist er eigentlich schon...)
1003    */
1004   if (dtaus_char(buf,4) == 'E') {
1005     if (dtaus_char(buf,4) == 'E') {
1006       fprintf(fcontrol, "\nEND {\n");
1007
1008       for (index=E_COUNT; index <= E_BLZ; index++) {
1009 #ifndef DEFAULT_EURO
1010         if (use_euro && index == E_VAL)
1011           index = E_EUR;
1012 #else
1013         if (!use_euro && index == E_VAL)
1014           index = E_DM;
1015 #endif
1016
1017         bufp = buf + recE[index].pos;
1018         memcpy(tmp, bufp, recE[index].len); tmp[recE[index].len] = '\0';
1019
1020 #ifndef DEFAULT_EURO
1021         if (index == E_VAL || index == E_EUR)
1022 #else
1023         if (index == E_VAL || index == E_DM)
1024 #endif
1025           printctln(fcontrol, recE[E_VAL].name, strip_zeros(string2real(tmp)));
1026         else
1027           printctln(fcontrol, recE[index].name, strip_zeros(tmp));
1028 #ifndef DEFAULT_EURO
1029           if (use_euro && index == E_EUR)
1030             index = E_VAL;
1031 #else
1032           if (!use_euro && index == E_DM)
1033             index = E_VAL;
1034 #endif
1035       }
1036
1037       fprintf(fcontrol, "}\n");
1038     } else {
1039       fprintf (stderr, "Das ist kein Abschlußdatensatz.\n");
1040       return;
1041     }
1042   } else {
1043     fprintf (stderr, "Der Abschlußdatensatz ist leer oder kaputt.\n");
1044     return;
1045   }
1046   fclose(fcontrol);
1047   fclose(fdtaus);
1048 }
1049
1050 int control2dtaus (char *ccontrol, char *cdtaus, char *cbeleg, char *ccheck)
1051 {
1052   FILE *fdtaus, *fcontrol, *fbeleg, *fcheck;
1053   void *buf;
1054   char *ident;
1055   int  recindex;
1056   char tmp[30];
1057   char line[100];
1058   char *valA[A_LEN], *valC[C_LEN];
1059   int count;
1060   bigint sum_val, sum_blz, sum_kto, bi;
1061   char **text = NULL;
1062   char *cp;
1063   int textindex = 0;
1064   int len, i;
1065
1066   if (!cdtaus) {
1067     if (!(fdtaus = fopen("dtaus0.txt", "w")))
1068       return 0;
1069   } else {
1070     if (!strcmp (cdtaus, "-"))
1071       fdtaus = stdout;
1072     else
1073       if (!(fdtaus = fopen(cdtaus, "w")))
1074         return 0;
1075   }
1076   if (!ccontrol) {
1077     if (!(fcontrol = fopen("dtaus0.ctl", "r")))
1078       if (!(fcontrol = fopen("DTAUS0.CTL", "r")))
1079         return 0;
1080   } else {
1081     if (!strcmp (ccontrol, "-"))
1082       fcontrol = stdin;
1083     else
1084       if (!(fcontrol = fopen(ccontrol, "r")))
1085         return 0;
1086   }
1087   if (!cbeleg) {
1088     if (!(fbeleg = fopen("dtaus0.doc", "w")))
1089       return 0;
1090   } else {
1091     if (!(fbeleg = fopen(cbeleg, "w")))
1092       return 0;
1093   }
1094   if (!ccheck)
1095     fcheck = stdout;
1096   else
1097     if (!(fcheck = fopen(ccheck, "w")))
1098       return 0;
1099
1100
1101   if (!(buf = (char *)malloc (512)))
1102     return 0;
1103
1104   /* 
1105    * Record A lesen
1106    */
1107   memset (valA, 0, sizeof(valA));
1108   control_nextline ((void *)line, 100, fcontrol);
1109   ident = extract_ident(line);
1110   if (!strcmp(ident, "begin") && (line[0] == '{')) {
1111     control_nextline ((void *)line, 100, fcontrol);
1112     while (strlen(line) && line[0] != '}') {
1113       ident = extract_ident(line);
1114       if ((recindex = rec_index(ident, REC_A)) != -1)
1115         {
1116         if (recA[recindex].type != IGN)
1117           if ((valA[recindex] = (char *)malloc (strlen(line)+1)))
1118             strcpy(valA[recindex], line);
1119         } else {
1120           if (! strcasecmp (ident, "euro"))
1121             use_euro = 1;
1122           if (! strcasecmp (ident, "dm"))
1123             use_euro = 0;
1124         }
1125       control_nextline ((void *)line, 100, fcontrol);
1126     }
1127     if (((recindex = rec_index("art", REC_A)) != -1) && valA[recindex] && strlen(valA[recindex])) {
1128       fprintf(fbeleg, "\n\n");
1129       fprintf(fbeleg, "\n    Begleitzettel\n\n");
1130       fprintf(fbeleg, "\n    Belegloser Datentraegeraustausch\n\n");
1131       if (valA[recindex][0] == 'L')
1132         fprintf(fbeleg, "\n    Sammeleinziehungsauftrag\n\n");
1133       else if (valA[recindex][0] == 'G')
1134         fprintf(fbeleg, "\n    Sammelueberweisungsauftrag\n\n");
1135       else
1136         fprintf(fbeleg, "\n    Sammelauftrag\n\n");
1137       fprintf(fbeleg, "\n    VOL ........................:\n");
1138       fprintf(fbeleg, "\n    Erstellungsdatum ...........: %s\n", get_date());
1139       if (valA[A_TODO]) {
1140         fprintf(fbeleg, "\n    Ausfuehrugsdatum ...........: %s\n", valA[A_TODO]);
1141       }
1142       if (use_euro)
1143         fprintf(fbeleg, "\n    Waehrung ...................: Euro\n");
1144       else
1145         fprintf(fbeleg, "\n    Waehrung ...................: DM\n");
1146     }
1147     if (!dtaus_writeA(fdtaus, valA)) {
1148       fprintf (stderr, "Konnte den Anfangsdatensatz nicht schreiben.\n");
1149       return 0;
1150     }
1151
1152     fprintf (fcheck, "\n\n\n");
1153     if (valA[recindex][0] == 'L')
1154       fprintf (fcheck, "    Sammeleinziehungsauftrag\n\n");
1155     else if (valA[recindex][0] == 'G')
1156       fprintf (fcheck, "    Sammelueberweisungsauftrag\n\n");
1157     else
1158       fprintf (fcheck, "    Sammelauftrag\n\n");
1159     fprintf (fcheck, "    Erstellungsdatum : %s\n\n", get_date());
1160     if (use_euro)
1161       fprintf (fcheck, "    Waehrung         : Euro\n\n\n");
1162     else
1163       fprintf (fcheck, "    Waehrung         : DM\n\n\n");
1164     fprintf (fcheck, "     %-10s  %-8s  %-30s   %12s\n", "Kontonr.", "BLZ", "Name", "Betrag");
1165     fprintf (fcheck, "    --------------------------------------------------------------------\n");
1166   } else {
1167     fprintf (stderr, "Datei fängt nicht mit dem Anfangsdatensatz (BEGIN) an.\n");
1168     return 0;
1169   }
1170
1171   /* 
1172    * Record C lesen
1173    */
1174   count = 0;
1175   sum_val = bigint_int(0);
1176   sum_blz = bigint_int(0);
1177   sum_kto = bigint_int(0);
1178   memset (valC, 0, sizeof(valC));
1179   control_nextline ((void *)line, 100, fcontrol);
1180   if (line[0] == '{') {
1181     while (strlen(line) && line[0] == '{') {
1182       control_nextline ((void *)line, 100, fcontrol);
1183       if (text) {
1184         for (textindex=0; textindex < MAX_TEXT && text[textindex]; textindex++)
1185           free (text[textindex]);
1186         free (text);
1187         text = NULL;
1188       }
1189       while (strlen(line) && line[0] != '}') {
1190         ident = extract_ident(line);
1191         if ((recindex = rec_index(ident, REC_C)) != -1)
1192           if (recC[recindex].type != IGN) {
1193             /*
1194              * Special exception to support multiple Text fields
1195              */
1196             if (recindex == C_TEXT && valC[recindex]) {
1197               if (!text) {
1198                 if ((text = (char **)malloc ((MAX_TEXT+1) * sizeof (char *))) == NULL)
1199                   return 0;
1200                 else {
1201                   textindex = 0;
1202                   memset (text, 0, (MAX_TEXT+1) * sizeof (char *));
1203                 }
1204               }
1205               if (textindex < MAX_TEXT) {
1206                 if ((cp = (char *)malloc (strlen (line) + 1))) {
1207                   strcpy (cp, line);
1208                   cp[strlen (line)] = '\0';
1209                   text[textindex++] = cp;
1210                 }
1211               }
1212             } else {
1213               len = strlen(line);
1214               if (recindex == C_VAL) {
1215                 /* Convert commast to dots for later processing */
1216                 for (i=0; line[i]; i++) if (line[i] == ',') line[i] = '.';
1217
1218                 if ((cp = index (line, '.')) == NULL) {
1219                   if (!(valC[recindex] = (char *)malloc (strlen(line)+4)))
1220                     return 0;
1221                   sprintf (valC[recindex], "%s.00", line);
1222                 } else if ( ((len = cp - line + 3)) < strlen (line)) {
1223                   if (!(valC[recindex] = (char *)malloc (len+1)))
1224                     return 0;
1225                   strncpy (valC[recindex], line, len);
1226                   valC[recindex][len] = '\0';
1227                 } else {
1228                   if (!(valC[recindex] = (char *)malloc (strlen(line)+1)))
1229                     return 0;
1230                   strcpy(valC[recindex], line);
1231                 }
1232               } else {
1233                 if ((valC[recindex] = (char *)malloc (strlen(line)+1)))
1234                   strcpy(valC[recindex], line);
1235                 else
1236                   return 0;
1237               }
1238             }
1239           }
1240         control_nextline ((void *)line, 100, fcontrol);
1241       }
1242       if (!dtaus_writeC(fdtaus, valA, valC, text)) {
1243         fprintf (stderr, "Konnte den regulären Datensatz nicht schreiben.\n");
1244         return 0;
1245       }
1246       count++;
1247       bi = bigint_string(real2string(valC[C_VAL])); sum_val = bigint_add(sum_val, bi);
1248       bi = bigint_string(valC[C_BLZ]); sum_blz = bigint_add(sum_blz, bi);
1249       bi = bigint_string(valC[C_KTO]); sum_kto = bigint_add(sum_kto, bi);
1250
1251       fprintf (fcheck, "     %10s  %8s  %-30s   %12s\n", valC[C_KTO], valC[C_BLZ], valC[C_NAME], valC[C_VAL]);
1252       for (recindex=0; recindex<C_LEN; recindex++)
1253         if (valC[recindex])
1254           free(valC[recindex]);
1255       memset (valC, 0, sizeof(valC));
1256       control_nextline ((void *)line, 100, fcontrol);
1257     }
1258   } else {
1259     fprintf (stderr, "Kein regulärer Datensatz?\n");
1260     return 0;
1261   }
1262
1263   /* 
1264    * Record E lesen
1265    */
1266   dtaus_writeE(fdtaus, count, sum_val, sum_blz, sum_kto);
1267   fprintf (fcheck, "    --------------------------------------------------------------------\n");
1268   bigint_sprintf (tmp, "%s", sum_val);
1269   fprintf (fbeleg, "\n    Anzahl .....................: %d\n", count);
1270   recindex=strlen(tmp);
1271   tmp[recindex+1] = '\0';
1272   tmp[recindex] = tmp[recindex-1];
1273   tmp[recindex-1] = tmp[recindex-2];
1274   tmp[recindex-2] = '.';
1275   fprintf (fcheck, "     %-52s %14s\n", "Summe", tmp);
1276   fprintf (fbeleg, "\n    Summe ......................: %s\n", tmp);
1277   bigint_sprintf (tmp, "%s", sum_kto);
1278   fprintf (fbeleg, "\n    Kontrollsumme Kontonummern .: %s\n", tmp);
1279   bigint_sprintf (tmp, "%s", sum_blz);
1280   fprintf (fbeleg, "\n    Kontrollsumme Bankleitzahlen: %s\n", tmp);
1281   fprintf (fbeleg, "\n    Unsere Kontonummer .........: %s\n", valA[A_KTO]);
1282   fprintf (fbeleg, "\n    Unsere Bankleitzahl ........: %s\n", valA[A_BLZ]);
1283   fprintf (fbeleg, "\n\n\n\n\n    __________________________________________________\n");
1284   fprintf (fbeleg, "    Ort, Datum                     Unterschrift\n");
1285   for (recindex=0; recindex<A_LEN; recindex++)
1286     if (valA[recindex])
1287       free(valA[recindex]);
1288   fclose(fdtaus);
1289   fclose(fcontrol);
1290   fclose(fbeleg);
1291   if (ccheck)
1292     fclose(fcheck);
1293   return count;
1294 }