?login_element?

Subversion Repositories NedoOS

Rev

Rev 344 | Blame | Compare with Previous | Last modification | View Log | Download

  1.         DEVICE ZXSPECTRUM128
  2.         include "../_sdk/sys_h.asm"
  3.  
  4. COLOR=7
  5.        
  6.         macro STRPUSH
  7. ;hl=string addr
  8.         xor a
  9.         push af
  10.          ld a,(hl)
  11.          inc hl
  12.          or a
  13.          push af
  14.         jr nz,$-4
  15.         pop af
  16. ;в стеке лежит \0, текст (без терминатора)
  17.         endm
  18.        
  19.         macro STRPOP
  20. ;hl=string addr
  21.         ld d,h
  22.         ld e,l
  23.          pop af
  24.          ld (hl),a
  25.          inc hl
  26.          or a
  27.         jr nz,$-4
  28.         ex de,hl ;hl=string addr, de не важен
  29.         call strmirror
  30.         endm
  31.        
  32.         org PROGSTART
  33. cmd_begin
  34.         ld sp,0xc000;0x4000 ;не должен опускаться ниже 0x3b00! иначе возможна порча OS
  35.         ld e,6 ;textmode
  36.         OS_SETGFX
  37.        
  38.         ;ld e,COLOR
  39.         ;OS_CLS
  40.  
  41.         ld hl,COMMANDLINE ;command line
  42.         call skipword
  43.         call skipspaces
  44.         ld a,(hl)
  45.         or a
  46.         jp z,noautoload
  47. ;проверяем, это *.tar или файл/директория? если файл/директория, то её надо паковать
  48.         push hl
  49.         call findlastdot ;out: de = after last dot or start
  50.         pop hl
  51.         or a
  52.         sbc hl,de
  53.         add hl,de
  54.         jr z,notar
  55.         ld a,(de)
  56.         or 0x20
  57.         cp 't'
  58.         jr nz,notar
  59.         inc de
  60.         ld a,(de)
  61.         or 0x20
  62.         cp 'a'
  63.         jr nz,notar
  64.         inc de
  65.         ld a,(de)
  66.         or 0x20
  67.         cp 'r'
  68.         jr nz,notar
  69.         jp untar
  70. notar
  71. ;это не *.tar
  72.         ld de,filename
  73.         call strcopy
  74. ;формируем имя архива (отрезаем расширение, если есть, и приписываем справа .tar)
  75. ;надо взять только после слеша (чтобы архив был в текущей директории):
  76.         ld hl,filename
  77.         call findlastslash. ;de=after last slash or start
  78.         ex de,hl
  79.         ld de,tarname
  80.         call strcopy
  81.         dec de
  82.        push de ;de=at terminator        
  83.         ld hl,tarname
  84.         push hl
  85.         call findlastdot
  86.         pop hl
  87.         or a
  88.         sbc hl,de
  89.         add hl,de
  90.         jr z,tarname_nolastdot
  91. ;проверяем, что эта точка относится к расширению, т.е. после неё нет слэшей
  92.         ld h,d
  93.         ld l,e ;de=after last dot
  94. tarname_checkext0
  95.         ld a,(hl)
  96.         inc hl
  97.         cp '/'
  98.         jr z,tarname_nolastdot
  99.         or a
  100.         jr nz,tarname_checkext0
  101.         dec de ;de=at last dot
  102.        pop af
  103.        push de
  104. tarname_nolastdot
  105.        pop de ;de=at terminator or last dot        
  106.         ld hl,ttar
  107.         call strcopy
  108.  
  109. ;создаём архив
  110.         ld de,tarname
  111.         call SAVECREATE
  112.         or a
  113.         jp nz,openerror
  114.  
  115. ;filename=имя файла с путём
  116. ;пусть мы находимся в той же директории, что пакуемый файл (в данном случае пакуемая директория), в filename уже нет пути:
  117.         ld hl,filename
  118.         call findlastslash. ;out: de = after last slash or start
  119.         ld hl,filename
  120.         or a
  121.         sbc hl,de
  122.         jr z,nopathinfilename
  123.         push de
  124.         dec de
  125.         xor a
  126.         ld (de),a ;instead of slash
  127.         ld hl,filename
  128.         ld de,cmdprompt
  129.         call strcopy
  130.         ld de,cmdprompt
  131.         OS_CHDIR
  132.         pop hl
  133.         ld de,filename
  134.         call strcopy
  135. nopathinfilename
  136.         xor a
  137.         ld (cmdprompt),a
  138. ;filename=имя файла без пути, выбрана директория файла, cmdprompt пустой
  139.         ld hl,filename
  140.         ld de,filenametoopen
  141.         call strcopy
  142.         call taraddfile
  143.        ld hl,tallok
  144.        call prtext
  145.         jr tarclosearchive
  146. openfileerror
  147.        ld hl,terroropeningfile
  148.        call prtext
  149. tarclosearchive
  150.         call SAVECLOSE
  151.  
  152.         jp quit
  153.        
  154. tallok
  155.         db "All OK",0x0d,0x0a,0
  156. terroropeningfile
  157.         db "Error opening file",0x0d,0x0a,0
  158.  
  159. taraddfile  
  160.         ld hl,filename
  161.         call prtext
  162.         call prcrlf
  163. ;filenametoopen=имя файла, который надо открыть в текущей директории
  164. ;filename=имя файла, которое надо положить в архив
  165. ;делаем заголовок файла
  166.         ld hl,tarfileheader
  167.         ld bc,100*256
  168.         ld (hl),c
  169.         inc hl
  170.         djnz $-2
  171.         ld hl,filename
  172.         ld de,tarfileheader
  173.         ld b,100
  174. tarmkfilename0
  175.         ld a,(hl)
  176.         or a
  177.         jr z,tarmkfilenameq
  178.         ld (de),a
  179.         inc hl
  180.         inc de
  181.         djnz tarmkfilename0
  182. tarmkfilenameq
  183.  
  184. ;открываем файл
  185. ;время можно прочитать и из директории, а открыть её как файл нельзя
  186.         ld de,filenametoopen
  187.         OS_GETFILETIME ;out: ix=date, hl=time
  188.         or a
  189.         jp nz,openfileerror
  190.  
  191.         call dos2unixtime ;out: dehl=UNIX time
  192.         ld bc,tarfiletimeoctal_end
  193.         ld a,11
  194.         call wroctaldehl_adigits
  195.        
  196.         ld de,filenametoopen
  197.         call openstream_file
  198.         or a
  199.         ld a,(filehandle)
  200.         ld b,a
  201.        push bc
  202.         jp nz,tardir;openfileerror ;4=no file, 5=no path, 13=no drive, 20=it's a directory (было тоже 4)
  203.  
  204.         OS_GETFILESIZE ;dehl=filesize
  205.        
  206. ;dehl=filesize
  207.         ld a,'0'
  208.         ld (tarfileordir),a
  209.         call tarwrsizeheader
  210. ;tarwritefile
  211. ;пакуем файл
  212. ;dehl=size
  213. writefile0
  214.         ld a,d
  215.         or e
  216.         ld bc,0x4000
  217.         call z,minhl_bc_tobc
  218. ;bc=save size
  219.         ld a,b
  220.         or c
  221.         jr z,writefileq
  222.         push de
  223.         push hl
  224.         push bc
  225.          ;push bc ;save size
  226. ;0x200 -> 0x200
  227. ;0x201 -> 0x400
  228.         dec bc
  229.         ld a,b
  230.         add a,2
  231.         and 0xfe
  232.         ld h,a ;0..1->2, 2..3->4
  233.         ld de,0xc000
  234.         ld l,e;0
  235. ;DE = Buffer address, HL = Number of bytes to read
  236.          push hl
  237.         push de
  238.         call readstream_file
  239. ;hl=actual size
  240.         pop de
  241.          pop hl ;save size
  242.         call SAVE
  243.         pop bc
  244.         pop hl
  245.         pop de
  246.         or a
  247.         sbc hl,bc
  248.         jr nc,$+3
  249.         dec de
  250.         jr writefile0
  251. writefileq
  252.         ;jr $
  253.        pop bc ;b=file handle
  254.         OS_CLOSEHANDLE
  255.         ret
  256.        
  257.        
  258. tardir
  259.         ld a,'5'
  260.         ld (tarfileordir),a
  261.         ld hl,0
  262.         ld d,h
  263.         ld e,l ;size=0
  264. ;dehl=filesize
  265.         call tarwrsizeheader ;записали директорию в архив
  266. ;допустим, что мы находимся в той же директории, что пакуемый файл (в данном случае пакуемая директория), в filename уже нет пути, cmdprompt пустой
  267. ;рекурсивно пакуем содержимое директории:
  268. ;- strpush cmdprompt
  269.         ;jr $
  270.         ld hl,cmdprompt
  271.         STRPUSH
  272. ;- cmdprompt = cmdprompt+filenametoopen
  273.         ;ld de,cmdprompt ;de=pointer to 64 byte (MAXPATH_sz!) buf
  274.         ;OS_GETPATH
  275.         ld hl,cmdprompt
  276. ;если непустой и в конце нет слеша, то добавим:
  277.         ;ld bc,0 ;чтобы точно найти терминатор
  278.         xor a
  279.        cp (hl)
  280.        jr z,tardirnoaddslash
  281.         ld b,a
  282.         ld c,a;0
  283.         cpir ;найдём обязательно, если длина=0, то bc=-1 и т.д.
  284.         dec hl ;на терминаторе
  285.         dec hl ;перед терминатором
  286.         ld a,'/'
  287.         cp (hl)
  288.         jr z,$+2+5
  289.          inc hl
  290.          ld (hl),a
  291.          inc hl
  292.          ld (hl),0
  293. tardirnoaddslash
  294.         ex de,hl
  295.         ld hl,filenametoopen
  296.         call strcopy ;TODO проверять переполнение буфера cmdprompt
  297. ;- chdir filenametoopen
  298.         ld de,filenametoopen
  299.         OS_CHDIR
  300. ;- читаем в цикле cpmname, из него формируем filenametoopen (dotname(cpmname)), filename (cmdprompt+dotname(cpmname)) - путь относительно корня директории!) и вызываем taraddfile
  301. ;        ld de,fcb
  302. ;        OS_SETDTA ;set disk transfer address = de
  303. ;        ;call makeemptymask
  304. ;        ld de,fcbmask
  305. ;        OS_FSEARCHFIRST
  306. ;        or a
  307. ;        jr nz,tardir0q
  308.        ld bc,0 ;номер файла в директории
  309. tardir0
  310.         ;jr $
  311.         push bc
  312.         call getdirfcb_bc
  313.         pop bc
  314.         jr nz,tardir0q
  315.        push bc ;номер файла в директории
  316.         ld hl,fcb_filename
  317.        ld a,(hl)
  318.        cp '.'
  319.        jr z,tardir0skip
  320.         ld de,filenametoopen
  321.         call cpmname_to_dotname
  322.         ld hl,cmdprompt
  323.         ld de,filename
  324.         call strcopy
  325.         ex de,hl
  326.         dec hl ;hl=terminator addr
  327. ;если в конце нет слеша, то добавим:
  328.         dec hl
  329.         ld a,'/'
  330.         cp (hl)
  331.         inc hl
  332.         jr z,$+4
  333.          ld (hl),a;'/'
  334.          inc hl
  335.         ex de,hl
  336.         ld hl,filenametoopen
  337.         call strcopy ;TODO проверять переполнение буфера filename
  338.         call taraddfile ;filenametoopen (dotname(cpmname)), filename (cmdprompt+dotname(cpmname))
  339. tardir0skip
  340.        ; ld de,fcb
  341.        ; OS_SETDTA ;set disk transfer address = de
  342.        ;  ;call makeemptymask ;в CP/M не нужно, но отсутствие вредит многозадачности
  343.        ;  ld de,fcbmask ;в CP/M не нужно, но отсутствие вредит многозадачности
  344.        ; OS_FSEARCHNEXT
  345.        pop bc
  346.        inc bc
  347.        ; or a
  348.        ; jr z,tardir0
  349.         jr tardir0
  350. tardir0q
  351. ;- strpop cmdprompt
  352.         ld hl,cmdprompt
  353.         STRPOP
  354. ;- chdir ..;cmdprompt
  355.         ld de,tdotdot;cmdprompt
  356.         OS_CHDIR
  357.        ld hl,tdirclosed
  358.        call prtext
  359.         jp writefileq
  360.        
  361. tdirclosed
  362.         db "Directory closed",0x0d,0x0a,0
  363.  
  364. tdotdot
  365.         db "..",0
  366.        
  367. getdirfcb_bc
  368. ;bc=file number in current dir to read to fcb
  369. ;nz=error
  370.         push bc
  371.         ld de,fcb
  372.         OS_SETDTA
  373.         ld de,fcbmask
  374.         OS_FSEARCHFIRST ;de = pointer to unopened FCB (filename with ????????), read matching FCB to DTA
  375.         pop bc
  376.         or a
  377.         ret nz
  378.        
  379. getdirfcb_bc0
  380.         ld a,b
  381.         or c
  382.         ret z
  383.         dec bc
  384.         push bc
  385.         ld de,fcb
  386.         OS_SETDTA
  387.         ld de,fcbmask
  388.         OS_FSEARCHNEXT ;(NOT CP/M!!!)de = pointer to unopened FCB (filename with ????????), read matching FCB to DTA
  389.         pop bc
  390.         or a
  391.         jr z,getdirfcb_bc0
  392.         ret
  393.        
  394. tarwrsizeheader
  395.         push de
  396.         push hl
  397.        
  398.         ld bc,tarfilesizeoctal_end
  399.         ld a,11
  400.         call wroctaldehl_adigits
  401.  
  402.         call wrheaderchecksum
  403.         ld de,tarfileheader
  404.         ld hl,0x200
  405.         call SAVE
  406.        
  407.         pop hl
  408.         pop de
  409.         ret
  410.  
  411. MULWORD
  412. ;out: HLBC=DE*BC
  413.         LD HL,0
  414.         LD A,17
  415. MULWOR0 RR B
  416.         RR C
  417.         DEC A
  418.         RET Z
  419.         JR NC,$+3
  420.         ADD HL,DE
  421.         RR H
  422.         RR L
  423.         JR MULWOR0
  424.  
  425. countdays_month
  426. ;d=year since 1970 (0 for 1970)
  427. ;e=month (1..12)
  428. ;out: a=days
  429.         ld a,e
  430.         cp 2
  431.         jr z,countdays_feb
  432.         push de
  433.         push hl
  434.         ld d,0
  435.         ld hl,tdays_month-1
  436.         add hl,de
  437.         ld a,(hl)
  438.         pop hl
  439.         pop de
  440.         ret
  441. countdays_feb
  442.         ld a,d
  443.         sub 2
  444.         and 3
  445.         ld a,28
  446.         ret nz
  447.         inc a
  448.         ret
  449.        
  450. tdays_month        
  451.         db 31
  452.         db 28
  453.         db 31
  454.         db 30
  455.         db 31
  456.         db 30
  457.         db 31
  458.         db 31
  459.         db 30
  460.         db 31
  461.         db 30
  462.         db 31
  463.  
  464. dos2unixtime
  465. ;ix=date, hl=time
  466. ;out: dehl=UNIX time
  467. ;DOS date, time to UNIX time (seconds since beginning of 1970)
  468.         ;jr $
  469.         push hl ;time
  470.         ld a,lx
  471.         push af
  472.         ld hl,0 ;число дней
  473.         ld a,hx
  474.         srl a
  475.         add a,10
  476.         ld d,a ;d=year since 1970 (0 for 1970)
  477. ;в цикле по годам прибавлять число дней, соответствующее годам
  478.         ;jr z,dos2unixtime_noyear
  479.         push de
  480.         ld b,d
  481.         ld d,0 ;year 1970
  482. dos2unixtime_years0
  483.         ld a,d
  484.         sub 2
  485.         and 3
  486.         ld a,365&0xff
  487.         jr nz,$+3
  488.         inc a
  489.         add a,l
  490.         ld l,a
  491.         adc a,h
  492.         sub l
  493.         ld h,a
  494.         inc h
  495.         inc d ;year 1971 etc... don't add current year
  496.         djnz dos2unixtime_years0
  497.         pop de
  498. ;dos2unixtime_noyear
  499. ;в цикле по месяцам прибавлять число дней, соответствующее месяцам
  500.         add ix,ix
  501.         add ix,ix
  502.         add ix,ix
  503.         ld a,hx
  504.         and 0x0f
  505.         ld b,a ;e=month (1..12)
  506.         dec b
  507.         jr z,dos2unixtime_nomonth
  508.         ld e,1
  509. dos2unixtime_months0
  510. ;e=month (1..12)
  511.         call countdays_month ;out: a=days
  512.         add a,l
  513.         ld l,a
  514.         adc a,h
  515.         sub l
  516.         ld h,a
  517.         inc e
  518.         djnz dos2unixtime_months0
  519. dos2unixtime_nomonth
  520.         pop af
  521.         and 0x1f ;day (1..31)
  522.         dec a
  523. ;потом прибавить (day-1) (т.к. дни у нас с единицы)
  524.         add a,l
  525.         ld l,a
  526.         adc a,h
  527.         sub l
  528.         ld h,a ;hl=число дней с начала 1970
  529. ;потом умножить на 86400 (0x15180) / 2
  530.         ex de,hl
  531.         ld bc,86400/2
  532.         call MULWORD ;out: HLBC=DE*BC
  533.         ld d,b
  534.         ld e,c
  535.         ex de,hl ;dehl = days*86400/2
  536.         pop bc ;time
  537. ;потом прибавить (3600/2*hour) + (60/2*minute) + (second/2) = 30*(60*hour + minute) + (second/2)
  538.         push de
  539.         push hl ;dehl = days*86400/2
  540.  
  541.         ld a,b
  542.         rra
  543.         rra
  544.         rra
  545.         and 0x1f ;hour
  546.         ld l,a
  547.         ld h,0
  548.         add hl,hl
  549.         add hl,hl
  550.         ld d,h
  551.         ld e,l ;hour*4
  552.         add hl,hl
  553.         add hl,hl
  554.         add hl,hl
  555.         add hl,hl ;hour*64
  556.         sbc hl,de ;hl = hour*60
  557.        
  558.         ld a,c
  559.         rla
  560.         rl b
  561.         rla
  562.         rl b
  563.         rla
  564.         rl b
  565.         ld a,b
  566.         and 0x3f ;minute
  567.         add a,l
  568.         ld l,a
  569.         adc a,h
  570.         sub l
  571.         ld h,a ;hl = (60*hour + minute)
  572.  
  573.         add hl,hl
  574.         ld d,h
  575.         ld e,l ;*2
  576.         add hl,hl
  577.         add hl,hl
  578.         add hl,hl
  579.         add hl,hl ;*32
  580.         sbc hl,de ;*30
  581. ;hl = 30*(60*hour + minute)
  582.  
  583.         ld a,c
  584.         and 0x1f ;second/2
  585.         ld c,a
  586.         ld b,0
  587.         add hl,bc
  588.        
  589.         pop bc
  590.         pop de ;debc = days*86400/2
  591.  
  592.         add hl,bc
  593.         jr nc,$+3
  594.         inc de
  595.        
  596. ;потом умножить на 2
  597.         add hl,hl
  598.         rl e
  599.         rl d ;dehl=UNIX time
  600.         ret
  601.  
  602. unix2dostime
  603. ;dehl=UNIX time
  604. ;out: ix=date, hl=time
  605. ;UNIX time (seconds since beginning of 1970) to DOS date, time
  606.         ;jr $
  607. ;поделить на 2 (т.к. в DOS только двойные секунды)
  608.         srl d
  609.         rr e
  610.         rr h
  611.         rr l
  612. ;поделить на 86400/2 - в остатке время
  613.         push de
  614.         ld de,86400/2
  615.         exx
  616.         pop hl
  617.         ld de,0
  618.         exx
  619.         call ldiv ; hl'hl = hl'hl / de'de ; de'de = hl'hl % de'de
  620. ;hl=дни
  621.         push de ;de=двойные секунды
  622.  
  623. ;в цикле по годам вычитать число дней, соответствующее годам
  624.         ld d,-1 ;year 1970-1
  625. unix2dostime_years0
  626.         inc d ;d=0 = year 1970 etc
  627.         ld a,d
  628.         sub 2
  629.         and 3
  630.         ld bc,365
  631.         jr nz,$+3
  632.         inc bc
  633.         or a
  634.         sbc hl,bc
  635.         jr nc,unix2dostime_years0
  636.         add hl,bc
  637. ;d=year
  638. ;hl=days
  639.  
  640. ;в цикле по месяцам вычитать число дней, соответствующее месяцам
  641.         ld e,0
  642. unix2dostime_months0
  643.         inc e ;e=month (1..12)
  644.         call countdays_month ;out: a=days
  645.         ld c,a
  646.         ld b,0
  647.         or a
  648.         sbc hl,bc
  649.         jr nc,unix2dostime_months0
  650.         add hl,bc
  651. ;d=year since 1970
  652. ;e=month=1..12
  653. ;hl=days
  654.         ld a,d
  655.         sub 10
  656.         jr nc,$+3
  657.         xor a ;year < 1980
  658.         ld d,a
  659.         inc l ;day (1..31)
  660.         ld a,e ;month
  661.         add a,a
  662.         add a,a
  663.         add a,a
  664.         add a,a
  665.         add a,a
  666.         rl d
  667.         ld hx,d
  668.         or l
  669.         ld lx,a
  670. ;ix = DOS date: %YYYYYYYM MMMDDDDD
  671.        
  672.         pop hl ;hl=двойные секунды
  673.  
  674. ;в цикле по часам вычитать число 3600/2
  675.         ld bc,3600/2
  676.         xor a ;NC
  677. unix2dostime_hours0
  678.         inc a
  679.         sbc hl,bc
  680.         jr nc,unix2dostime_hours0
  681.         add hl,bc
  682.         dec a ;a=hours = 0..23
  683.         add a,a
  684.         add a,a
  685.         add a,a
  686.         ld d,a ;d=hours<<3
  687.        
  688. ;в цикле по минутам вычитать число 60/2
  689.         ld bc,60/2
  690.         xor a ;NC
  691. unix2dostime_minutes0
  692.         inc a
  693.         sbc hl,bc
  694.         jr nc,unix2dostime_minutes0
  695.         add hl,bc ;l=seconds/2
  696.         dec a ;a=minutes = 0..59
  697.         ld e,a
  698.         xor a
  699.         rr e
  700.         rra
  701.         rr e
  702.         rra
  703.         rr e
  704.         rra
  705.         or l
  706.         ld l,a
  707.         ld a,d ;d=hours<<3
  708.         or e
  709.         ld h,a
  710. ;hl = DOS time: %hhhhhmmm mmmsssss
  711.         ret
  712.  
  713. ; версия от 2006-12-18T15:11:28+0300
  714. ; Беззнаковое 32-разрядное деление
  715. ; функция состоит из двух частей:
  716. ; 1. 32-разрядное делимое и 16-разрядный
  717. ;    делитель.
  718. ; 2. 32-раздядное делимое и 32-разрядный
  719. ;    делитель.
  720. ; hl'hl = hl'hl / de'de
  721. ; de'de = hl'hl % de'de
  722. ldiv
  723.         push hl
  724.         xor a
  725.         ld l, a
  726.         ld h, a
  727.         sub e
  728.         ld e, a
  729.  ld a, h
  730.         sbc a, d
  731.         ld d, a
  732.         exx
  733.         pop bc
  734.         ld a, 0
  735.         sbc a, e
  736.         ld e, a
  737.         sbc a, d  ; de'de=0-divisor
  738.         sub e
  739.         ld d, a
  740.         and e
  741.         inc a     ; Z=short divisor
  742.         push hl
  743.         ld hl, 0  ; hl'hl=reminder
  744.         exx
  745.         pop bc
  746.         ld a, b   ; a,c,bc'=divident
  747.  
  748.         jr nz, ldiv_long
  749.  
  750.  
  751.     ; divisor = -00de
  752.         ld b, 8
  753.         rla
  754. ldivs0
  755.         rl l
  756.         add hl, de
  757.         jr c, ldivs1
  758.         sbc hl, de
  759. ldivs1  rla
  760.         djnz ldivs0
  761.  
  762.            ld b, c
  763.            ld c, a
  764.            ld a, b
  765.            ld b, 8
  766.         rla
  767. ldivs2
  768.         adc hl, hl
  769.         add hl, de
  770.         jr c, ldivs3
  771.         sbc hl, de
  772. ldivs3  rla
  773.         djnz ldivs2
  774.         jr ldiv_long1
  775.  
  776.  
  777.    ; divisor=-de'de
  778. ldiv_long
  779.         call ldiv_8
  780.            ld b, c
  781.            ld c, a
  782.            ld a, b
  783.         call ldiv_8
  784. ldiv_long1
  785.            exx
  786.            exa
  787.            ld a, b
  788.            exa
  789.            ld b, a
  790.            exa
  791.            exx
  792.         call ldiv_8
  793.            exx
  794.            exa
  795.            ld a, c
  796.            exa
  797.            ld c, a
  798.            exa
  799.            exx
  800.         call ldiv_8
  801.  
  802.   ; result=c,bc',a -> hl'hl
  803.   ; reminder=hl'hl -> de'de
  804.  
  805.         ex de, hl
  806.         ld l, a
  807.         ld a, c
  808.         exx
  809.         ex de, hl
  810.         ld h, a
  811.         ld l, b
  812.         ld a, c
  813.         exx
  814.         ld h, a
  815.         ret
  816.  
  817.  
  818. ; hl'hl=reminder
  819. ; de'de=divisor
  820. ; a=divident
  821. ldiv_8
  822.         ld b, 8
  823.         rla
  824. ldiv_8_0
  825.         adc hl, hl
  826.         exx
  827.         adc hl, hl
  828.         exx
  829.         add hl, de
  830.         exx
  831.         adc hl, de
  832.         exx
  833.         jr c, ldiv_8_1
  834.         sbc hl, de
  835.         exx
  836.         sbc hl, de
  837.         exx
  838. ldiv_8_1
  839.         rla
  840.         djnz ldiv_8_0
  841.         ret
  842.          
  843.        
  844. untar
  845.         ;ld (filenameaddr),hl
  846. ;command line = "texted <file to load>"
  847.         ;ld (texted_filenameaddr),hl
  848.         ex de,hl ;de=drive/path/file
  849.         call openstream_file
  850.         or a
  851.         jp nz,openerror
  852.  
  853. readtar0
  854.         ld de,header
  855.          xor a
  856.          ld (de),a
  857.         ld hl,0x200
  858.         call readstream_file
  859.         ld hl,header
  860.         ld a,(hl)
  861.         or a
  862.         jp z,untarend
  863.          xor a
  864.          ld (header+100),a ;на всякий случай, если длина имени = 100
  865.         ld de,filename
  866.         call copyname328
  867.        
  868.         ld a,(header+0x09c) ;type (0=file, 5=dir)
  869.         cp '5'
  870.         jr nz,readtar_nodir
  871. ;убираем слеш в конце
  872.         ld hl,filename
  873.         push hl
  874.         xor a
  875.         ld b,-1
  876.         cpir
  877.         ld a,'/'
  878.         dec hl ;на терминаторе
  879.         dec hl ;перед терминатором
  880.         sub (hl)
  881.         jr nz,$+3
  882.         ld (hl),a ;0
  883.         pop de ;ld de,filename
  884.         OS_MKDIR
  885.         jr readtar0
  886. readtar_nodir
  887.  
  888.         ld bc,header+0x07c ;size in octal (TODO size in bytes - найти пример)
  889.         call readoctal_dehl
  890.        
  891. ;dehl=size
  892.         push de
  893.         push hl
  894.         ld de,filename
  895.         call SAVECREATE
  896.         pop hl
  897.         pop de
  898. readfile0
  899.         ld a,d
  900.         or e
  901.         ld bc,0x4000
  902.         call z,minhl_bc_tobc
  903. ;bc=save size
  904.         ld a,b
  905.         or c
  906.         jr z,readfileq
  907.         push de
  908.         push hl
  909.         push bc
  910.          push bc ;save size
  911. ;0x200 -> 0x200
  912. ;0x201 -> 0x400
  913.         dec bc
  914.         ld a,b
  915.         add a,2
  916.         and 0xfe
  917.         ld h,a ;0..1->2, 2..3->4
  918.         ld de,0xc000
  919.         ld l,e;0
  920. ;DE = Buffer address, HL = Number of bytes to read
  921.         push de
  922.         call readstream_file
  923. ;hl=actual size
  924.         pop de
  925.          pop hl ;save size
  926.         call SAVE
  927.         pop bc
  928.         pop hl
  929.         pop de
  930.         or a
  931.         sbc hl,bc
  932.         jr nc,$+3
  933.         dec de
  934.         jr readfile0
  935. readfileq
  936.         call SAVECLOSE
  937.  
  938.         ld bc,header+0x088 ;time in octal
  939.         call readoctal_dehl
  940.         call unix2dostime
  941.         ld de,filename
  942.         OS_SETFILETIME
  943.  
  944.         jp readtar0
  945. untarend
  946.         call closestream_file
  947. noautoload
  948. openerror
  949. quit
  950.         QUIT
  951.  
  952. readoctal_dehl
  953.         ld hl,0
  954.         ld d,h
  955.         ld e,l
  956. readtar_getsize0
  957.         ld a,(bc)
  958.         inc bc
  959.         sub '0'
  960.         ret c ;jr c,readtar_getsizeq
  961.         add hl,hl
  962.         rl e
  963.         rl d
  964.         add hl,hl
  965.         rl e
  966.         rl d
  967.         add hl,hl
  968.         rl e
  969.         rl d
  970.         adc a,l
  971.         ld l,a
  972.         ld a,h
  973.         adc a,0
  974.         ld h,a
  975.         jr nc,$+3
  976.         inc de
  977.         jr readtar_getsize0
  978. ;readtar_getsizeq
  979.         ret
  980.  
  981. minhl_bc_tobc
  982.         or a
  983.         sbc hl,bc
  984.         add hl,bc
  985.         ret nc ;bc<=hl
  986.         ld b,h
  987.         ld c,l
  988.         ret
  989.        
  990. skipword
  991. ;hl=string
  992. ;out: hl=terminator/space addr
  993. getword0
  994.         ld a,(hl)
  995.         or a
  996.         ret z
  997.         cp ' '
  998.         ret z
  999.         inc hl
  1000.         jr getword0
  1001.  
  1002. skipspaces
  1003. ;hl=string
  1004. ;out: hl=after last space
  1005.         ld a,(hl)
  1006.         cp ' '
  1007.         ret nz
  1008.         inc hl
  1009.         jr skipspaces
  1010.  
  1011. prtext
  1012. ;out: hl=after terminator
  1013. prtext0
  1014.         ld a,(hl)
  1015.         inc hl
  1016.         or a
  1017.         ret z
  1018.         push hl
  1019.         PRCHAR
  1020.         pop hl
  1021.         jp prtext0
  1022.  
  1023. prcrlf
  1024.         ld a,0x0d
  1025.         PRCHAR
  1026.         ld a,0x0a
  1027.         PRCHAR
  1028.         ret
  1029.        
  1030. ;hl = size to write
  1031. ;de = addr
  1032. SAVE
  1033.         ld a,(savefilehandle)
  1034.         ld b,a
  1035.         push iy
  1036.         OS_WRITEHANDLE
  1037.         pop iy
  1038.         ret
  1039.  
  1040. SAVECREATE
  1041.         push iy
  1042.         OS_CREATEHANDLE
  1043. ;b=new file handle
  1044.         push af
  1045.         ld a,b
  1046.         ld (savefilehandle),a
  1047.         pop af
  1048.         pop iy
  1049.         ret
  1050.  
  1051. SAVECLOSE
  1052.         push iy
  1053. savefilehandle=$+1
  1054.         ld b,0
  1055.         OS_CLOSEHANDLE
  1056.         pop iy
  1057.         ret
  1058.  
  1059. ;hl = poi to filename in string
  1060. ;out: de = after last dot or start
  1061. findlastdot
  1062.         ld d,h
  1063.         ld e,l ;de = after last dot
  1064. findlastdot0
  1065.         ld a,[hl]
  1066.         inc hl
  1067.         or a
  1068.         ret z
  1069.         cp '.'
  1070.         jr nz,findlastdot0
  1071.         jr findlastdot
  1072.  
  1073. ;hl = poi to filename in string
  1074. ;out: de = after last slash or start
  1075. findlastslash.
  1076. nfopenfnslash.
  1077.         ld d,h
  1078.         ld e,l ;de = after last slash or start
  1079. nfopenfnslash0.
  1080.         ld a,[hl]
  1081.         inc hl
  1082.         or a
  1083.         ret z
  1084.         cp '/'
  1085.         jr nz,nfopenfnslash0.
  1086.         jr nfopenfnslash.
  1087.  
  1088. copyname328
  1089. ;hl->de
  1090. copyname328_element
  1091.         ld b,32
  1092. copyname328_0
  1093.         ld a,(hl)
  1094.         inc hl
  1095.         or a
  1096.         jr z,copyname328_q
  1097.         cp '/'
  1098.         jr z,copyname328_endelement
  1099.         cp '.'
  1100.         jr z,copyname328_ext
  1101.         ld (de),a
  1102.         inc de
  1103.         djnz copyname328_0
  1104. ;8 chars of name copied, wait for dot or slash or terminator
  1105. copyname328_skipname0
  1106.         ld a,(hl)
  1107.         inc hl
  1108.         or a
  1109.         jr z,copyname328_q
  1110.         cp '/'
  1111.         jr z,copyname328_endelement
  1112.         cp '.'
  1113.         jr nz,copyname328_skipname0
  1114. copyname328_ext
  1115.         ld (de),a ;'.'
  1116.         inc de
  1117.         ld b,8
  1118. copyname328_ext0
  1119.         ld a,(hl)
  1120.         inc hl
  1121.         or a
  1122.         jr z,copyname328_q
  1123.         cp '/'
  1124.         jr z,copyname328_endelement
  1125.         cp '.'
  1126.         jr z,copyname328_skipext0
  1127.         ld (de),a
  1128.         inc de
  1129.         djnz copyname328_ext0
  1130. copyname328_skipext0
  1131.         ld a,(hl)
  1132.         inc hl
  1133.         or a
  1134.         jr z,copyname328_q
  1135.         cp '/'
  1136.         jr nz,copyname328_skipext0
  1137. copyname328_endelement
  1138.         ld (de),a ;'/'
  1139.         inc de
  1140.         jr copyname328_element
  1141. copyname328_q
  1142.         ld (de),a ;0
  1143.         ret
  1144.        
  1145. strcopy
  1146. ;hl->de
  1147. ;out: hl,de after terminator
  1148. strcopy0
  1149.         ld a,(hl)
  1150.         ldi
  1151.         or a
  1152.         jr nz,strcopy0
  1153.         ret
  1154.  
  1155. ;oldtimer
  1156. ;        dw 0
  1157.  
  1158. ttar
  1159.         db ".tar",0
  1160.  
  1161. wrheaderchecksum
  1162.         ld hl,tarfileheaderchecksumoctal
  1163.         ld bc,0x820
  1164.         ld (hl),c
  1165.         inc hl
  1166.         djnz $-2 ;fill with spaces
  1167.         ld hl,tarfileheader
  1168.         ld de,0
  1169.         ld bc,0x200
  1170. countheaderchecksum0
  1171.         ld a,(hl)
  1172.         add a,e
  1173.         ld e,a
  1174.         adc a,d
  1175.         sub e
  1176.         ld d,a
  1177.         cpi
  1178.         jp pe,countheaderchecksum0
  1179. ;de=checksum
  1180.         ex de,hl
  1181.         ld de,0 ;dehl=checksum
  1182.         ld bc,tarfileheaderchecksumoctal_end
  1183.         xor a
  1184.         ld (bc),a
  1185.         dec bc
  1186.         ld a,' '
  1187.         ld (bc),a
  1188.         ld a,6
  1189.         jp wroctaldehl_adigits
  1190.        
  1191. wroctaldehl_adigits
  1192. ;bc=text end (after last digit)
  1193. ;a=number of digits
  1194. wroctaldehl_adigits0
  1195.         push af
  1196.         call wroctaldehl_dig
  1197.         pop af
  1198.         dec a
  1199.         jr nz,wroctaldehl_adigits0
  1200.         ret
  1201.  
  1202. wroctaldehl_dig
  1203. ;bc=text end (after last digit)
  1204.         srl d
  1205.         rr e
  1206.         rr h
  1207.         rr l
  1208.         rra
  1209.         srl d
  1210.         rr e
  1211.         rr h
  1212.         rr l
  1213.         rra
  1214.         srl d
  1215.         rr e
  1216.         rr h
  1217.         rr l
  1218.         rra
  1219.         rlca
  1220.         rlca
  1221.         rlca
  1222.         and 7
  1223.         add a,'0'
  1224.         dec bc
  1225.         ld (bc),a
  1226.         ret
  1227.        
  1228. strmirror
  1229. ;hl=string addr
  1230.         ld d,h
  1231.         ld e,l
  1232.         call strlen
  1233.         ld b,h
  1234.         ld c,l
  1235.          ld a,b
  1236.          or c
  1237.          ret z
  1238. ;de=начало, bc=hl=длина
  1239.         ;ld h,b
  1240.         ;ld l,c
  1241.         add hl,de ;hl=конец+1
  1242.         srl b
  1243.         rr c ;bc=wid/2
  1244. mirrorbytes0
  1245.         dec hl
  1246.         ld a,(de)
  1247.         ldi
  1248.         dec hl
  1249.         ld (hl),a
  1250.         jp pe,mirrorbytes0
  1251.         ret
  1252.        
  1253. cpmname_to_dotname
  1254. ;hl -> de
  1255.         push hl
  1256.         ld b,8
  1257. cpmname_to_dotname0
  1258.         ld a,(hl)
  1259.         cp ' '
  1260.         jr z,cpmname_to_dotname0q
  1261.         ld (de),a
  1262.         inc hl
  1263.         inc de
  1264.         djnz cpmname_to_dotname0
  1265. cpmname_to_dotname0q
  1266.         pop hl
  1267.         ld bc,8
  1268.         add hl,bc ;hl=pointer to ext
  1269.         ld a,(hl)
  1270.         cp ' '
  1271.         jr z,cpmname_to_dotnameq
  1272.         ld a,'.'
  1273.         ld (de),a
  1274.         inc de
  1275.         ld  c,3
  1276.         ldir
  1277. cpmname_to_dotnameq
  1278.         xor a
  1279.         ld (de),a
  1280.         ret
  1281.  
  1282. strlen
  1283. ;hl=str
  1284. ;out: hl=length
  1285.         ld bc,0 ;чтобы точно найти терминатор
  1286.         xor a
  1287.         cpir ;найдём обязательно, если длина=0, то bc=-1 и т.д.
  1288.         ld hl,-1
  1289.         or a
  1290.         sbc hl,bc
  1291.         ret
  1292.        
  1293. tarfileheader
  1294.         ds 100 ;filename
  1295.         db "0000777",0
  1296.         db "0000000",0
  1297.         db "0000000",0
  1298. ;tarfilesizeoctal=$
  1299.         db "00000000000",0 ;11 цифр = 33 бита
  1300. tarfilesizeoctal_end=$-1
  1301. ;tarfiletimeoctal=$
  1302.         db "00000000000",0 ;11 цифр = 33 бита
  1303. tarfiletimeoctal_end=$-1
  1304. tarfileheaderchecksumoctal=$
  1305.         db "007147 ",0
  1306. tarfileheaderchecksumoctal_end=$-1
  1307. tarfileordir=$
  1308.         db "0" ;0=file, 5=dir
  1309.         ds tarfileheader+0x101-$
  1310.         db "ustar"
  1311.         ds tarfileheader+0x200-$
  1312.  
  1313.         db 0 ;для затирания, если нет пути
  1314. filename
  1315.         db "depkfile.fil"
  1316.         ds filename+256-$ ;для длинных имён
  1317.  
  1318. filenametoopen
  1319.         ds 256
  1320.        
  1321. fcb
  1322.         ds FCB_sz
  1323. fcb_filename=fcb+FCB_FNAME        
  1324.  
  1325. fcbmask
  1326.         db 0
  1327.         db "???????????"
  1328.         ds FCB_sz-11-1
  1329. fcbmask_filename=fcbmask+FCB_FNAME
  1330.  
  1331. cmdprompt
  1332.         ds 256
  1333.  
  1334. tarname
  1335.         ds 256
  1336.        
  1337.         include "../_sdk/file.asm"
  1338.        
  1339. cmd_end
  1340. header
  1341.         ;ds 512
  1342.  
  1343.         display "Size ",/d,cmd_end-cmd_begin," bytes"
  1344.  
  1345.         savebin "tar.com",cmd_begin,cmd_end-cmd_begin
  1346.        
  1347.         ;LABELSLIST "../us/user.l"
  1348.