1414 along with this program. If not, see <http://www.gnu.org/licenses/>. */
1515
1616#include <time.h>
17+ #include <ctype.h>
1718#include <utime.h>
1819#include <stdio.h>
1920#include <errno.h>
@@ -42,7 +43,9 @@ static const char *type_name[] =
4243
4344#define MAX 518
4445static word_t block [MAX ];
46+ static word_t * data = & block [6 ];
4547static int extract = 0 ;
48+ static word_t tape_flags = 0 ;
4649
4750static FILE * list ;
4851static FILE * info ;
@@ -58,8 +61,7 @@ static int tape_number;
5861static int file_number ;
5962static int page_number ;
6063static int record_number ;
61- static int bfmsg = 3 ;
62- static int format = 4 ;
64+ static int format ;
6365
6466/*
6567Format:
@@ -167,7 +169,7 @@ close_file (void)
167169 utimes (file_path , timestamp );
168170}
169171
170- /* Convert WAITS file name to an acceptable Unix name. */
172+ /* Convert TENEX file name to an acceptable Unix name. */
171173static char *
172174mangle (char * string )
173175{
@@ -184,6 +186,18 @@ mangle (char *string)
184186 return string ;
185187}
186188
189+ static char *
190+ upcase (char * string )
191+ {
192+ char * p = string ;
193+ while (* p )
194+ {
195+ * p = toupper (* p );
196+ p ++ ;
197+ }
198+ return string ;
199+ }
200+
187201static char *
188202find (char * * string , const char * required , char * fail )
189203{
@@ -216,7 +230,7 @@ find (char **string, const char *required, char *fail)
216230/* Convert a file name from the command line to a TOPS-20 file name. */
217231static const char *
218232unmangle (char * file_name , char * device , char * name ,
219- int protection , const char * author )
233+ int protection , const char * author , int * generation )
220234{
221235 char original_name [100 ];
222236 char * directories [100 ];
@@ -230,28 +244,36 @@ unmangle (char *file_name, char *device, char *name,
230244 * d = find (& name , "/" , NULL );
231245 while (* d ++ != NULL );
232246
233- if (d - directories > 1 && format == 0 )
247+ if (d - directories > 2 && format == 0 )
234248 return "TENEX doesn't support subdirectories" ;
235249
236250 file = find (& name , "." , name );
237251 type = find (& name , ".;" , name );
238252 version = find (& name , ";" , name );
253+ if (version )
254+ {
255+ char * end ;
256+ long x = strtol (version , & end , 10 );
257+ if (end > version )
258+ * generation = x ;
259+ }
239260
240261 if (device )
241262 file_name += sprintf (file_name , "%s:" , device );
242263 if (directories [0 ] != NULL )
243264 {
244265 file_name += sprintf (file_name , "<" );
245266 for (d = & directories [0 ]; * d != NULL ; d ++ , sep = "." )
246- file_name += sprintf (file_name , "%s%s" , sep , * d );
267+ file_name += sprintf (file_name , "%s%s" , sep , upcase ( * d ) );
247268 file_name += sprintf (file_name , ">" );
248269 }
249270 if (file )
250- file_name += sprintf (file_name , "%s" , file );
271+ file_name += sprintf (file_name , "%s" , upcase (file ));
272+ file_name += sprintf (file_name , "." );
251273 if (type )
252- file_name += sprintf (file_name , ". %s" , type );
253- if ( version )
254- file_name += sprintf ( file_name , "%c%s" , format == 0 ? ';' : '.' , version );
274+ file_name += sprintf (file_name , "%s" , upcase ( type ) );
275+ file_name += sprintf ( file_name , "%c%u" ,
276+ format == 0 ? ';' : '.' , * generation );
255277 file_name += sprintf (file_name , ";P%06o" , protection );
256278 if (author )
257279 file_name += sprintf (file_name , ";A%s" , author );
@@ -409,11 +431,11 @@ read_tape_header (FILE *f, word_t word)
409431
410432 word = read_record (f , word );
411433
412- //fprintf (stderr, "006: %012llo format\n", block[6 ]);
434+ //fprintf (stderr, "006: %012llo format\n", data[0 ]);
413435
414- read_asciz (name , & block [ 9 ]);
436+ read_asciz (name , & data [ 3 ]);
415437 fprintf (stderr , "DUMPER tape #%d, %s, " , right (block [2 ]), name );
416- print_timestamp (stderr , block [ 8 ]);
438+ print_timestamp (stderr , data [ 2 ]);
417439 fputc ('\n' , stderr );
418440
419441 return word ;
@@ -428,7 +450,7 @@ read_file (int offset)
428450 if (offset != 0206 )
429451 return ;
430452
431- read_asciz (name , & block [ 6 ]);
453+ read_asciz (name , & data [ 0 ]);
432454 p = strchr (name , ';' );
433455 if (p )
434456 * p = 0 ;
@@ -440,7 +462,7 @@ read_file (int offset)
440462 (block [offset + 011 ] >> 24 ) & 077 );
441463
442464#if 0
443- fprintf (stderr , "006: %012llo file name\n" , block [ 6 ]);
465+ fprintf (stderr , "006: %012llo file name\n" , data [ 0 ]);
444466 fprintf (stderr , "Timestamp, last write: " );
445467 print_timestamp (stderr , block [offset + 5 ]);
446468 fputc ('\n' , stderr );
@@ -529,28 +551,42 @@ write_asciz (const char *string, word_t *data)
529551}
530552
531553static void
532- write_record (FILE * f , int type , word_t flags )
554+ write_mark (void )
555+ {
556+ tape_flags = START_FILE ;
557+ }
558+
559+ static void
560+ write_record (FILE * f , int type )
533561{
534562 word_t checksum = 0 ;
535563 int i ;
536564
537- fprintf (stderr , "\nWrite record %s" , type_name [type ]);
565+ if (tape_flags & START_FILE )
566+ fprintf (debug , "\nWrite mark" );
567+
568+ fprintf (debug , "\nWrite record %s" , type_name [type ]);
569+
570+ memset (block , 0 , 6 * sizeof (word_t ));
538571
539- block [1 ] = 0 ;
540572 block [2 ] = (saveset_number << 18 ) | tape_number ;
573+ if (format > 0 )
574+ block [2 ] |= saveset_number ;
541575 block [3 ] = page_number ;
542- fprintf (stderr , ", page %d" , page_number );
576+ fprintf (debug , ", page %d, record %d " , page_number , record_number );
543577 if (0 )
544578 block [3 ] |= file_number << 18 ;
545579 block [4 ] = (- type ) & 0777777777777LL ;
546580 block [5 ] = record_number ++ ;
547581
548582 for (i = 0 ; i < MAX ; i ++ )
549583 checksum = sum (checksum , block [i ]);
550- block [0 ] = (checksum ^ 0777777777777LL ) | START_RECORD | flags ;
584+ block [0 ] = (checksum ^ 0777777777777LL ) | START_RECORD | tape_flags ;
585+ tape_flags = 0 ;
551586
552- for (i = 0 ; i < MAX ; i ++ )
553- write_word (f , block [i ]);
587+ write_word (f , block [0 ]);
588+ for (i = 1 ; i < MAX ; i ++ )
589+ write_word (f , block [i ] & 0777777777777LL );
554590
555591 memset (block , 0 , sizeof block );
556592}
@@ -562,7 +598,7 @@ get_page (FILE *f)
562598 int ok = 0 ;
563599 int i ;
564600
565- memset (block + 6 , 0 , 512 * sizeof (word_t ));
601+ memset (data , 0 , 512 * sizeof (word_t ));
566602
567603 /* If the first word indicates EOF, return "no page".
568604 In other cases, return a partial or full page. */
@@ -571,7 +607,7 @@ get_page (FILE *f)
571607 word = get_word (f );
572608 if (word == -1 )
573609 return ok ;
574- block [ 6 + i ] = word ;
610+ data [ i ] = word ;
575611 ok = 1 ;
576612 }
577613
@@ -607,11 +643,11 @@ write_file (FILE *f, char *name)
607643 generation = 1 ;
608644 author = "OPERATOR" ;
609645
610- error = unmangle (file_name , device , name , protection , author );
646+ error = unmangle (file_name , device , name , protection , author , & generation );
611647 if (error )
612- fprintf (debug , "\nERROR: Bad file name \"%s\": %s" , file_name , error );
648+ fprintf (stderr , "\nERROR: Bad file name \"%s\": %s" , file_name , error );
613649 else
614- fprintf (debug , "\nFILE: %s" , file_name );
650+ fprintf (list , "\n %s" , file_name );
615651
616652 memset (fdb , 0 , sizeof fdb );
617653 //000 //header word
@@ -626,67 +662,83 @@ write_file (FILE *f, char *name)
626662 fdb [013 ] = tops20_timestamp (st .st_ctime ); //timestamp: creation
627663 fdb [014 ] = tops20_timestamp (st .st_mtime ); //timestamp: last user write
628664 fdb [015 ] = tops20_timestamp (st .st_atime ); //timestamp: last nonwrite access
629-
630- write_asciz (file_name , block + 6 );
631- memcpy (block + 0206 , fdb , sizeof fdb );
665+ write_asciz (file_name , data );
666+ memcpy (data + 0200 , fdb , sizeof fdb );
632667 page_number = 0 ;
633- write_record (f , FLHD , 0 );
668+ write_record (f , FLHD );
634669
635670 while (get_page (input ))
636671 {
637- write_record (f , DATA , 0 );
672+ write_record (f , DATA );
638673 page_number ++ ;
639674 }
640675 fclose (input );
641676
642- memcpy (block + 6 , fdb , sizeof fdb );
677+ memcpy (data , fdb , sizeof fdb );
643678 page_number = 0 ;
644- write_record (f , FLTR , 0 );
679+ write_record (f , FLTR );
680+ if (format == 0 )
681+ write_mark ();
645682}
646683
647684static void
648685write_usr (FILE * f )
649686{
650- write_record (f , USR , 0 );
687+ write_record (f , USR );
651688}
652689
653690static void
654691write_tape (FILE * f )
655692{
656- int i ;
657693 struct word_format * tmp = input_word_format ;
658694 input_word_format = output_word_format ;
659695 output_word_format = tmp ;
696+ int i , bfmsg = 0 ;
660697
661698 if (f == NULL )
662699 f = stdout ;
663700
664701 saveset_number = 0 ;
665702 tape_number = 1 ;
666703 file_number = 1 ;
667- record_number = 1 ;
668704
669- block [6 ] = format ;
670- block [7 ] = bfmsg ;
671- block [8 ] = tops20_timestamp (time (NULL ));
672- write_asciz ("Saveset name" , block + 6 + bfmsg );
673- write_record (f , TPHD , START_FILE );
705+ if (format == 0 )
706+ {
707+ record_number = 2 ;
708+ }
709+ else
710+ {
711+ record_number = 1 ;
712+ data [bfmsg ++ ] = format ;
713+ bfmsg ++ ;
714+ data [bfmsg ++ ] = tops20_timestamp (time (NULL ));
715+ data [1 ] = bfmsg ;
716+ }
717+ write_asciz ("Saveset name" , data + bfmsg );
718+
719+ write_record (f , TPHD );
720+ if (format == 0 )
721+ {
722+ write_mark ();
723+ record_number ++ ;
724+ }
674725
675726 for (i = 0 ; i < file_argc ; i ++ )
676727 {
677728 write_file (f , file_argv [i ]);
678729 file_number ++ ;
679730 }
680731
681- write_record (f , TPTR , 0 );
732+ write_record (f , TPTR );
733+ write_mark ();
682734 flush_word (f );
683735}
684736
685737static void
686738usage (const char * x )
687739{
688740 fprintf (stderr ,
689- "Usage: %s -c|-t|-x [-v789 ] [-Wformat] [-Cdir] [-f file]\n" , x );
741+ "Usage: %s -c|-t|-x [-v0123456 ] [-Wformat] [-Cdir] [-f file]\n" , x );
690742 usage_word_format ();
691743 exit (1 );
692744}
@@ -716,6 +768,14 @@ main (int argc, char **argv)
716768 list = stdout ;
717769 info = debug = stderr ;
718770
771+ /* If the program is called mini-something, default to mini-dumper
772+ format. Otherwise go with format 4 which is acceptable to a wide
773+ range of DUMPER versions. */
774+ if (strncasecmp (argv [0 ], "mini" , 4 ) == 0 )
775+ format = 0 ;
776+ else
777+ format = 4 ;
778+
719779 while ((opt = getopt (argc , argv , "ctvx012379f:W:C:" )) != -1 )
720780 {
721781 switch (opt )
0 commit comments