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