35ebd444821cf56a99c1187c12c85746ae312a78
[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 60
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 void dtaus_prepareA (char *buf)
459 {
460   int i;
461   time_t timer;
462   struct tm *loctime;
463   char tmp[10];
464
465   bzero (buf, 129);
466   timer = time ( NULL );
467   loctime = localtime(&timer);
468
469   buf[0] = '0';
470   buf[1] = '1';
471   buf[2] = '2';
472   buf[3] = '8';
473   buf[4] = 'A';
474   for (i=15;i<15+8; i++) buf[i] = '0';
475   sprintf(tmp, "%02d%02d%02d", loctime->tm_mday, loctime->tm_mon+1, loctime->tm_year % 100);
476   for (i=0; i<6; i++) buf[50+i] = tmp[i];
477   for (i=56;i<56+4; i++) buf[i] = ' ';
478   for (i=70;i<70+10; i++) buf[i] = '0';
479   for (i=80;i<80+48; i++) buf[i] = ' ';
480 }
481
482 void dtaus_prepareC (char *buf, int normaltext, int maxtext)
483 {
484   int i;
485   int appendix = 0;
486   div_t res;
487
488   bzero (buf, 257);
489   buf[0] = '0';
490
491   if (normaltext)
492     appendix = 1;
493   if (maxtext) {
494     res = div (maxtext, 4);
495     appendix += res.quot;
496     if (res.rem) appendix++;
497   }
498   i = 187 + (appendix * 29);
499
500   /* Bail out if the number is too large, shouldn't be possible though */
501   if (i>1000)
502     exit (1);
503
504   buf[1] = (i/100)+48;i-=(i/100)*100;
505   buf[2] = (i/10)+48;i-=(i/10)*10;
506   buf[3] = i+48;
507   buf[4] = 'C';
508
509   for (i=31;i<31+13; i++) buf[i] = '0';
510   buf[49] = ' ';
511   for (i=79;i<79+11; i++) buf[i] = '0';
512   for (i=90;i<90+3; i++) buf[i] = ' ';
513   for (i=120;i<120+8; i++) buf[i] = ' ';
514   for (i=182;i<182+3; i++) buf[i] = ' ';
515   for (i=185;i<185+2; i++) buf[i] = '0';
516   for (i=187;i<187+(29*2); i++) buf[i] = ' ';
517   for (i=245;i<245+11; i++) buf[i] = ' ';
518 }
519
520 void dtaus_prepareE (char *buf)
521 {
522   int i;
523
524   bzero (buf, 129);
525   buf[0] = '0';
526   buf[1] = '1';
527   buf[2] = '2';
528   buf[3] = '8';
529   buf[4] = 'E';
530   for (i=5;i<5+5; i++) buf[i] = ' ';
531   for (i=64;i<64+13; i++) buf[i] = '0';
532   for (i=77;i<77+51; i++) buf[i] = ' ';
533 }
534
535 int dtaus_writeA(FILE *f, char **values)
536 {
537   char buf[129];
538   char tmp[30];
539   int i;
540   
541   for (i=0; (recA[i].name); i++)
542     if ((recA[i].type == REQ) && !values[i]) {
543       fprintf (stderr, "Anfangsdatensatz ist nicht vollständig, kein %s.\n", recA[i].name);
544       return 0;
545     }
546   if (!(((values[A_TRANS][0] == 'L')||(values[A_TRANS][0] == 'G'))
547         &&((values[A_TRANS][1] == 'B')||(values[A_TRANS][1] == 'K')))) {
548     fprintf (stderr, "Ungültiger Typ, nur LK, GK, LB oder GB erlaubt.\n");
549     return 0;
550   }
551
552   i=A_NAME;if (values[i] && strlen(values[i]) > recA[i].len)
553     values[i][recA[i].len] = '\0';
554
555   dtaus_prepareA(buf);
556   buf[5] = values[A_TRANS][0];
557   buf[6] = values[A_TRANS][1];
558   sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[A_BLZ]),8));
559   for (i=0; i<8; i++) buf[recA[A_BLZ].pos+i] = tmp[i];
560   sprintf (tmp, "%-27s", upcase(values[A_NAME]));
561   for (i=0; i<27; i++) buf[recA[A_NAME].pos+i] = tmp[i];
562   sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[A_KTO]),10));
563   for (i=0; i<10; i++) buf[recA[A_KTO].pos+i] = tmp[i];
564
565   fputs(buf, f);
566   return 1;
567 }
568
569 int dtaus_writeC(FILE *f, char **valuesA, char **values, char **text)
570 {
571   char buf[257];
572   char appendix[129];
573   char tmp[30];
574   int i, k;
575   int maxtext = 0;
576   int fieldnr;
577   div_t res;
578
579   if (text)
580     for (maxtext=0;text[maxtext];maxtext++);
581
582 #if DEBUG
583   for (i=0; (recC[i].name); i++)
584     if (values[i])
585       printf ("%s: %s\n", recC[i].name, values[i]);
586 #endif
587
588   for (i=0; (recC[i].name); i++)
589     if ((recC[i].type == REQ) && !values[i]) {
590       fprintf (stderr, "Datensatz ist nicht vollständig, kein %s.\n", recC[i].name);
591       return 0;
592     }
593   sprintf (tmp, "%s", trans2string(values[C_TRANS]));
594   if (!strlen(tmp)) {
595     fprintf (stderr, "Ungültiger Typ, nur Abbuchung, Einzug, E-Cash, E-Cash-A, Gutschrift und Lohn erlaubt.\n");
596     return 0;
597   }
598
599   i=C_TEXT;if (values[i] && strlen(values[i]) > recC[i].len)
600     values[i][recC[i].len] = '\0';
601   i=C_ZWECK;if (values[i] && strlen(values[i]) > recC[i].len)
602     values[i][recC[i].len] = '\0';
603   i=C_MYNAM;if (values[i] && strlen(values[i]) > recC[i].len)
604     values[i][recC[i].len] = '\0';
605   i=C_TEXT;if (values[i] && strlen(values[i]) > recC[i].len)
606     values[i][recC[i].len] = '\0';
607   i=C_EXT;if (values[i] && strlen(values[i]) > recC[i].len)
608     values[i][recC[i].len] = '\0';
609
610   dtaus_prepareC (buf, values[C_TEXT] != NULL, maxtext);
611   for (i=0; i<5; i++) buf[recC[C_TRANS].pos+i] = tmp[i];
612   if (values[C_MYBLZ])
613     sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[C_MYBLZ]),8));
614   else
615     sprintf (tmp, "%s", padzeroclip (strip_nondigits (valuesA[A_BLZ]),8));
616   for (i=0; i<recC[C_MYBLZ].len; i++) buf[5+i] = tmp[i];
617   for (i=0; i<recC[C_MYBLZ].len; i++) buf[recC[C_MYBLZ].pos+i] = tmp[i];
618   sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[C_BLZ]),8));
619   for (i=0; i<recC[C_BLZ].len; i++) buf[recC[C_BLZ].pos+i] = tmp[i];
620   sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[C_KTO]),10));
621   for (i=0; i<recC[C_KTO].len; i++) buf[recC[C_KTO].pos+i] = tmp[i];
622   sprintf (tmp, "%s", padzeroclip (real2string(values[C_VAL]),11));
623   for (i=0; i<recC[C_VAL].len; i++) buf[recC[C_VAL].pos+i] = tmp[i];
624   if (values[C_MYKTO])
625     sprintf (tmp, "%s", padzeroclip (strip_nondigits (values[C_MYKTO]),10));
626   else
627     sprintf (tmp, "%s", padzeroclip (strip_nondigits (valuesA[A_KTO]),10));
628   for (i=0; i<recC[C_MYKTO].len; i++) buf[recC[C_MYKTO].pos+i] = tmp[i];
629   sprintf (tmp, "%-27s", upcase(values[C_NAME]));
630   for (i=0; i<recC[C_NAME].len; i++) buf[recC[C_NAME].pos+i] = tmp[i];
631   if (values[C_MYNAM])
632     sprintf (tmp, "%-27s", upcase(values[C_MYNAM]));
633   else
634     sprintf (tmp, "%-27s", upcase(valuesA[A_NAME]));
635   for (i=0; i<recC[C_MYNAM].len; i++) buf[recC[C_MYNAM].pos+i] = tmp[i];
636   sprintf (tmp, "%-27s", upcase(values[C_ZWECK]));
637   for (i=0; i<recC[C_ZWECK].len; i++) buf[recC[C_ZWECK].pos+i] = tmp[i];
638
639   if (values[C_TEXT]) {
640     buf[recC[C_TEXT].pos+0] = '0';
641     buf[recC[C_TEXT].pos+1] = '2';
642     sprintf (tmp, "%-27s", upcase(values[C_TEXT]));
643     for (i=0; i<recC[C_TEXT].len-2; i++) buf[recC[C_TEXT].pos+2+i] = tmp[i];
644   }
645
646   if (text) {
647     res = div (maxtext, 4);
648     i=res.quot;
649     if (res.rem) i++;
650
651     buf[185+0] = (i/10)+48;i-=(i/10)*10;
652     buf[185+1] = i+48;
653   }
654
655   fputs(buf, f);
656
657   if (text) {
658     fieldnr=0;
659     while (fieldnr<maxtext) {
660       memset (appendix, ' ', 128);
661       appendix[128] = '0';
662       for (k=0; k<4 && (fieldnr+k)<maxtext; k++) {
663         sprintf (tmp, "%-27s", upcase(text[fieldnr+k]));
664         appendix[k*29] = '0';
665         appendix[(k*29)+1] = '2';
666         for (i=0; i<recC[C_TEXT].len-2; i++) appendix[(k*29)+2+i] = tmp[i];
667       }
668       fputs(appendix, f);
669       fieldnr += k;
670     }
671   }
672
673   return 1;
674 }
675
676 int dtaus_writeE(FILE *f, int count, bigint sum, bigint blz, bigint kto)
677 {
678   char buf[129];
679   char tmp[30];
680   int i;
681   
682   dtaus_prepareE(buf);
683
684   sprintf (tmp, "%07d", count);
685   for (i=0; i<recE[E_COUNT].len; i++) buf[recE[E_COUNT].pos+i] = tmp[i];
686   bigint_sprintf (tmp, "%s", sum);
687   padzeroclip (tmp,13);
688   for (i=0; i<recE[E_VAL].len; i++) buf[recE[E_VAL].pos+i] = tmp[i];
689   bigint_sprintf (tmp, "%s", sum);
690   padzeroclip (tmp,13);
691   for (i=0; i<recE[E_VAL].len; i++) buf[recE[E_VAL].pos+i] = tmp[i];
692   bigint_sprintf (tmp, "%s", kto);
693   padzeroclip (tmp,17);
694   for (i=0; i<recE[E_KTO].len; i++) buf[recE[E_KTO].pos+i] = tmp[i];
695   bigint_sprintf (tmp, "%s", blz);
696   padzeroclip (tmp,17);
697   for (i=0; i<recE[E_BLZ].len; i++) buf[recE[E_BLZ].pos+i] = tmp[i];
698
699   fputs(buf, f);
700   return 1;
701 }
702
703 void printctln(FILE *f, char *field, char *value)
704 {
705   if (strlen(field) && strlen(value))
706     fprintf(f, "  %s\t%s\n", field, value);
707 }
708
709
710 /*
711  *  Third: Some high level routines
712  */
713
714 void dtaus2control (char *cdtaus, char *ccontrol)
715 {
716   FILE *fdtaus, *fcontrol;
717   void *buf;
718   void *bufp;
719   char tmp[30];
720   char x[30];
721   int index, countC;
722
723   if (!cdtaus) {{
724     if (!(fdtaus = fopen("DTAUS0.TXT", "r")))
725       if (!(fdtaus = fopen("dtaus0.txt", "r")))
726         return;
727   } else {
728     if (!strcmp (cdtaus, "-"))
729       fdtaus = stdin;
730     else
731       if (!(fdtaus = fopen(cdtaus, "r")))
732         return;
733   }
734   if (!ccontrol) 
735     fcontrol = stdout;
736   else
737     if (!strcmp (ccontrol, "-"))
738       fcontrol = stdout;
739     else
740       if (!(fcontrol = fopen(ccontrol, "w")))
741         return;
742   if (!(buf = (char *)malloc (512)))
743     return;
744
745   /* 
746    * Record A lesen
747    */
748   if (dtaus_nextrec(buf, fdtaus) == 1) {
749     if (dtaus_char(buf,4) == 'A') {
750       fprintf(fcontrol, "BEGIN {\n");
751       bufp = buf;
752
753       for (index=A_TRANS; index < A_DATE; index++) {
754         bufp = buf + recA[index].pos;
755         memcpy(tmp, bufp, recA[index].len); tmp[recA[index].len] = '\0';
756         printctln(fcontrol, recA[index].name, strip_zeros(strip_spaces(tmp)));
757       }
758
759       index = A_DATE; bufp = buf + recA[index].pos;
760       memcpy(tmp, bufp, recA[index].len); tmp[recA[index].len] = '\0';
761       printctln(fcontrol, recA[index].name, strip_spaces(tmp));
762
763       index = A_EURO; bufp = buf + recA[index].pos;
764       memcpy(tmp, bufp, recA[index].len); tmp[recA[index].len] = '\0';
765       printctln(fcontrol, recA[index].name, strip_zeros(strip_spaces(tmp)));
766
767       fprintf(fcontrol, "}\n\n");
768     } else {
769       fprintf (stderr, "Datei fängt nicht mit dem Anfangsdatensatz an.\n");
770       return;
771     }
772   } else {
773     fprintf (stderr, "Der Anfangsdatensatz ist kaputt.\n");
774     return;
775   }
776
777   /*
778    * Record C lesen
779    */
780   if (dtaus_nextrec(buf, fdtaus) == 1) {
781     while (dtaus_char(buf,4) == 'C') {
782       bufp = buf + 128;
783       if (dtaus_nextrec(bufp, fdtaus) == 1) {
784         fprintf(fcontrol, "{\n");
785
786         for (index=C_NAME; index <= C_EURO; index++) {
787           bufp = buf + recC[index].pos;
788           memcpy(tmp, bufp, recC[index].len); tmp[recC[index].len] = '\0';
789           if (index == C_VAL)
790             printctln(fcontrol, recC[index].name, strip_zeros(string2real(tmp)));
791           else if (index == C_TRANS)
792             printctln(fcontrol, recC[index].name, strip_zeros(string2trans(tmp)));
793           else
794             printctln(fcontrol, recC[index].name, strip_zeros(strip_spaces(tmp)));
795         }
796
797         for (index=C_TEXT; index <= C_EXT; index++) {
798           if (!(dtaus_char(buf,recC[index].pos) == ' ')) {
799             bufp = buf + recC[index].pos;
800             memcpy(x, bufp, 2); tmp[2] = '\0'; bufp+=2;
801             memcpy(tmp, bufp, recC[index].len-2); tmp[recC[index].len-2] = '\0';
802             printctln(fcontrol, string2ext(x), strip_spaces(tmp));
803           }
804         }
805
806         countC = dtaus_int(buf, 185, 2);
807         countC = countC<3?0:countC-2/4;
808         countC += countC%4>0?1:0;
809         /* FIXME: Erweiterungsfelder werden ignoriert */
810
811         fprintf(fcontrol, "}\n");
812       } else {
813         fprintf (stderr, "Der zweite Teil der Transaktion ist kaputt.\n");
814         return;
815       }
816       if (dtaus_nextrec(buf, fdtaus) != 1)
817         bzero (buf, sizeof(buf));
818     }
819   }
820
821   /*
822    * Record E lesen
823    *   (gelesen ist er eigentlich schon...)
824    */
825   if (dtaus_char(buf,4) == 'E') {
826     if (dtaus_char(buf,4) == 'E') {
827       fprintf(fcontrol, "END {\n");
828
829       for (index=E_COUNT; index <= E_BLZ; index++) {
830         bufp = buf + recE[index].pos;
831         memcpy(tmp, bufp, recE[index].len); tmp[recE[index].len] = '\0';
832         if (index == E_VAL)
833           printctln(fcontrol, recE[index].name, strip_zeros(string2real(tmp)));
834         else
835           printctln(fcontrol, recE[index].name, strip_zeros(tmp));
836       }
837
838       fprintf(fcontrol, "}\n");
839     } else {
840       fprintf (stderr, "Das ist kein Abschlußdatensatz.\n");
841       return;
842     }
843   } else {
844     fprintf (stderr, "Der Abschlußdatensatz ist leer oder kaputt.\n");
845     return;
846   }
847   fclose(fcontrol);
848   fclose(fdtaus);
849 }
850
851 int control2dtaus (char *ccontrol, char *cdtaus, char *cbeleg, char *ccheck)
852 {
853   FILE *fdtaus, *fcontrol, *fbeleg, *fcheck;
854   void *buf;
855   char *ident;
856   int  recindex;
857   char tmp[30];
858   char line[100];
859   char *valA[A_LEN], *valC[C_LEN];
860   int count;
861   bigint sum_val, sum_blz, sum_kto, bi;
862   char **text = NULL;
863   char *cp;
864   int textindex = 0;
865
866   if (!cdtaus) {
867     if (!(fdtaus = fopen("dtaus0.txt", "w")))
868       return 0;
869   } else {
870     if (!strcmp (cdtaus, "-"))
871       fdtaus = stdout;
872     else
873       if (!(fdtaus = fopen(cdtaus, "w")))
874         return 0;
875   }
876   if (!ccontrol) {
877     if (!(fcontrol = fopen("dtaus0.ctl", "r")))
878       if (!(fcontrol = fopen("DTAUS0.CTL", "r")))
879         return 0;
880   } else {
881     if (!strcmp (ccontrol, "-"))
882       fcontrol = stdin;
883     else
884       if (!(fcontrol = fopen(ccontrol, "r")))
885         return 0;
886   }
887   if (!cbeleg) {
888     if (!(fbeleg = fopen("dtaus0.doc", "w")))
889       return 0;
890   } else {
891     if (!(fbeleg = fopen(cbeleg, "w")))
892       return 0;
893   }
894   if (!ccheck)
895     fcheck = stdout;
896   else
897     if (!(fcheck = fopen(ccheck, "w")))
898       return 0;
899
900
901   if (!(buf = (char *)malloc (512)))
902     return 0;
903
904   /* 
905    * Record A lesen
906    */
907   bzero(valA, sizeof(valA));
908   control_nextline ((void *)line, 100, fcontrol);
909   ident = extract_ident(line);
910   if (!strcmp(ident, "begin") && (line[0] == '{')) {
911     control_nextline ((void *)line, 100, fcontrol);
912     while (strlen(line) && line[0] != '}') {
913       ident = extract_ident(line);
914       if ((recindex = rec_index(ident, REC_A)) != -1)
915         if (recA[recindex].type != IGN)
916           if ((valA[recindex] = (char *)malloc (strlen(line)+1)))
917             strcpy(valA[recindex], line);
918       control_nextline ((void *)line, 100, fcontrol);
919     }
920     if (((recindex = rec_index("art", REC_A)) != -1) && valA[recindex] && strlen(valA[recindex])) {
921       fprintf(fbeleg, "\n\n");
922       fprintf(fbeleg, "\n    Begleitzettel\n\n");
923       fprintf(fbeleg, "\n    Belegloser Datentraegeraustausch\n\n");
924       if (valA[recindex][0] == 'L')
925         fprintf(fbeleg, "\n    Sammeleinziehungsauftrag\n\n");
926       else if (valA[recindex][0] == 'G')
927         fprintf(fbeleg, "\n    Sammelueberweisungsauftrag\n\n");
928       else
929         fprintf(fbeleg, "\n    Sammelauftrag\n\n");
930       fprintf(fbeleg, "\n    VOL ........................:\n");
931       fprintf(fbeleg, "\n    Erstellungsdatum ...........: %s\n", get_date());
932       fprintf(fbeleg, "\n    Waehrung ...................: DM\n");
933     }
934     if (!dtaus_writeA(fdtaus, valA)) {
935       fprintf (stderr, "Konnte den Anfangsdatensatz nicht schreiben.\n");
936       return 0;
937     }
938
939     fprintf (fcheck, "\n\n\n");
940     if (valA[recindex][0] == 'L')
941       fprintf (fcheck, "    Sammeleinzeiehungsauftrag\n\n");
942     else if (valA[recindex][0] == 'G')
943       fprintf (fcheck, "    Sammelueberweisungsauftrag\n\n");
944     else
945       fprintf (fcheck, "    Sammelauftrag\n\n");
946     fprintf (fcheck, "    Erstellungsdatum : %s\n\n", get_date());
947     fprintf (fcheck, "    Waehrung         : DM\n\n\n");
948     fprintf (fcheck, "     %-10s  %-8s  %-30s   %12s\n", "Kontonr.", "BLZ", "Name", "Betrag");
949     fprintf (fcheck, "    --------------------------------------------------------------------\n");
950   } else {
951     fprintf (stderr, "Datei fängt nicht mit dem Anfangsdatensatz (BEGIN) an.\n");
952     return 0;
953   }
954
955   /* 
956    * Record C lesen
957    */
958   count = 0;
959   sum_val = bigint_int(0);
960   sum_blz = bigint_int(0);
961   sum_kto = bigint_int(0);
962   bzero(valC, sizeof(valC));
963   control_nextline ((void *)line, 100, fcontrol);
964   if (line[0] == '{') {
965     while (strlen(line) && line[0] == '{') {
966       control_nextline ((void *)line, 100, fcontrol);
967       if (text) {
968         for (textindex=0; textindex < MAX_TEXT && text[textindex]; textindex++)
969           free (text[textindex]);
970         free (text);
971         text = NULL;
972       }
973       while (strlen(line) && line[0] != '}') {
974         ident = extract_ident(line);
975         if ((recindex = rec_index(ident, REC_C)) != -1)
976           if (recC[recindex].type != IGN) {
977             /*
978              * Special exception to support multiple Text fields
979              */
980             if (recindex == C_TEXT && valC[recindex]) {
981               if (!text) {
982                 if ((text = (char **)malloc ((MAX_TEXT+1) * sizeof (char *))) == NULL)
983                   return 0;
984                 else {
985                   textindex = 0;
986                   memset (text, 0, (MAX_TEXT+1) * sizeof (char *));
987                 }
988               }
989               if (textindex < MAX_TEXT) {
990                 if ((cp = (char *)malloc (strlen (line) + 1))) {
991                   strcpy (cp, line);
992                   cp[strlen (line)] = '\0';
993                   text[textindex++] = cp;
994                 }
995               }
996             } else {
997               if ((valC[recindex] = (char *)malloc (strlen(line)+1)))
998                 strcpy(valC[recindex], line);
999               else
1000                 return 0;
1001             }
1002           }
1003         control_nextline ((void *)line, 100, fcontrol);
1004       }
1005       if (!dtaus_writeC(fdtaus, valA, valC, text)) {
1006         fprintf (stderr, "Konnte den regulären Datensatz nicht schreiben.\n");
1007         return 0;
1008       }
1009       count++;
1010       bi = bigint_string(real2string(valC[C_VAL])); sum_val = bigint_add(sum_val, bi);
1011       bi = bigint_string(valC[C_BLZ]); sum_blz = bigint_add(sum_blz, bi);
1012       bi = bigint_string(valC[C_KTO]); sum_kto = bigint_add(sum_kto, bi);
1013
1014       fprintf (fcheck, "     %10s  %8s  %-30s   %12s\n", valC[C_KTO], valC[C_BLZ], valC[C_NAME], valC[C_VAL]);
1015       for (recindex=0; recindex<C_LEN; recindex++)
1016         if (valC[recindex])
1017           free(valC[recindex]);
1018       bzero(valC, sizeof(valC));
1019       control_nextline ((void *)line, 100, fcontrol);
1020     }
1021   } else {
1022     fprintf (stderr, "Kein regulärer Datensatz?\n");
1023     return 0;
1024   }
1025
1026   /* 
1027    * Record E lesen
1028    */
1029   dtaus_writeE(fdtaus, count, sum_val, sum_blz, sum_kto);
1030   fprintf (fcheck, "    --------------------------------------------------------------------\n");
1031   bigint_sprintf (tmp, "%s", sum_val);
1032   fprintf (fbeleg, "\n    Anzahl .....................: %d\n", count);
1033   recindex=strlen(tmp);
1034   tmp[recindex+1] = '\0';
1035   tmp[recindex] = tmp[recindex-1];
1036   tmp[recindex-1] = tmp[recindex-2];
1037   tmp[recindex-2] = '.';
1038   fprintf (fcheck, "     %-52s %14s\n", "Summe", tmp);
1039   fprintf (fbeleg, "\n    Summe ......................: %s\n", tmp);
1040   bigint_sprintf (tmp, "%s", sum_kto);
1041   fprintf (fbeleg, "\n    Kontrollsumme Kontonummern .: %s\n", tmp);
1042   bigint_sprintf (tmp, "%s", sum_blz);
1043   fprintf (fbeleg, "\n    Kontrollsumme Bankleitzahlen: %s\n", tmp);
1044   fprintf (fbeleg, "\n    Unsere Kontonummer .........: %s\n", valA[A_KTO]);
1045   fprintf (fbeleg, "\n    Unsere Bankleitzahl ........: %s\n", valA[A_BLZ]);
1046   fprintf (fbeleg, "\n\n\n\n\n    __________________________________________________\n");
1047   fprintf (fbeleg, "    Ort, Datum                     Unterschrift\n");
1048   for (recindex=0; recindex<A_LEN; recindex++)
1049     if (valA[recindex])
1050       free(valA[recindex]);
1051   fclose(fdtaus);
1052   fclose(fcontrol);
1053   fclose(fbeleg);
1054   if (ccheck)
1055     fclose(fcheck);
1056   return count;
1057 }