(*~\Глагол\Отделы\Обмен\~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
(**)                             ОТДЕЛ Файл;
(*============================================================================*)
(* НАЗНАЧЕНИЕ: работа с файлами                                               *)
(* ОБОЗНАЧЕНИЯ: место - местоположение файла на определенном накопителе       *)
(*              путь  - местоположение файла или относительный путь к файлу   *)
(*============================================================================*)

ИСПОЛЬЗУЕТ
        (*  \Глагол\              *)
  ОС      ИЗ "..\..\Отделы\Обмен\",
        (*  \Глагол\              *)
 оЦепи    ИЗ "..\..\Отделы\Иное\";

ПОСТ
                                 (* наибольшие длины (с учетом конечного 0X): *)
  длПути-    = ОС.длПутиФ;   (* пути к файлу               *)
  длИмени-   = ОС.длИмениФ;  (* имени файла без типа файла *)
  длТипа-    = ОС.длТипаФ;   (* типа файла с начальной "." *)
  длПолного- = ОС.длПолногоФ;(* полного имени файла    *)
                                                           (* свойства файлов:*)
  сфОбычный-      = ОС.сфОбычный;
  сфТолькоЧтение- = ОС.сфТолькоЧтение;
  сфНевидимый-    = ОС.сфНевидимый;
  сфСистемный-    = ОС.сфСистемный;
  сфНазваниеДиска-= ОС.сфНазваниеДиска;
  сфКаталог-      = ОС.сфКаталог;
  сфАрхивный-     = ОС.сфАрхивный;

ВИД
  нПоиск-  = ОС.нПоискФ; (* системный набор для поиска файлов *)
  шцВремя- = ОС.шцВремяФ;(* время *)

  ВПути-    = ЦЕПЬ[Файл.длПути];
  ВИмени-   = ЦЕПЬ[Файл.длИмени];
  ВТипа-    = ЦЕПЬ[Файл.длТипа];
  ВПолного- = ЦЕПЬ[Файл.длПолного];


(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА ИсправитьИмя(имя+:ЦЕПЬ);
(*
 * Исправляет "/" на "\" и убирает повторы "\"
 *)
ПЕР
  ч,п,дл:ЦЕЛ;
  зн,зн1:ЗНАК;
УКАЗ
  дл:=ДЛИНА(имя);

  ч:=0;
  п:=0;
  зн1:=0X;
  ПОКА
       ч < дл
  ВЫП
    зн:=имя[ч];
    УВЕЛИЧИТЬ(ч);
    ЕСЛИ
         зн = "/"
    ТО
         зн:="\"
    КОН;
    ЕСЛИ
        (зн # "\") ИЛИ (зн1 # "\")
    ТО
      имя[п]:=зн;
      УВЕЛИЧИТЬ(п)
    КОН;
    зн1:=зн
  КОН;
  ЕСЛИ
       п < дл
  ТО
    имя[п]:=0X
  КОН
КОН ИсправитьИмя;

(*----------------------------------------------------------------------------*)
ЗАДАЧА ИсправитьМесто(имя+:ЦЕПЬ);
(*
 * Убирает по возможности ".." в местоположении файла.
 *)
ПЕР
  ч,п,послпалка,начпоз,дл:ЦЕЛ;
  зв,зн:ЗНАК;
  точек:ЦЕЛ;
 (*...........подЗадача..*)
  ЗАДАЧА ЧП();          (* Читаем, пишем вперёд *)
  УКАЗ
    ЕСЛИ ч < дл ТО
      зв:=имя[ч];
      имя[п]:=зв;
      УВЕЛИЧИТЬ(ч);
      УВЕЛИЧИТЬ(п)
    ИНАЧЕ
      зв:=0X
    КОН
  КОН ЧП;
 (*...........подЗадача..*)
  ЗАДАЧА ЧВ();          (* Читаем вперёд *)
  УКАЗ
    ЕСЛИ ч < дл ТО
      зв:=имя[ч];
      УВЕЛИЧИТЬ(ч)
    ИНАЧЕ
      зв:=0X
    КОН
  КОН ЧВ;
 (*...........подЗадача..*)
  ЗАДАЧА ЧН();          (* Читаем назад *)
  УКАЗ
    ЕСЛИ п > начпоз ТО
      УМЕНЬШИТЬ(п);
      зн:=имя[п]
    ИНАЧЕ
      зн:=0X
    КОН
  КОН ЧН;

УКАЗ
  ИсправитьИмя(имя);
  дл:=ДЛИНА(имя);
                                           (* не рассматриваем накопитель *)
  начпоз:=оЦепи.ПозицияЗнака(":",имя,0)+1;
  ч:=начпоз;
  п:=начпоз;
  ЧП();
  ПОКА
       ч < дл
  ВЫП
    ЕСЛИ зв = "." ТО
                                           (* считаем точки *)
      точек:=0;
      ПОКА зв = "." ВЫП
        УВЕЛИЧИТЬ(точек);
        ЧП()
      КОН;
                                           (* откатываем палки *)
      послпалка:=п;
      ЧН();
      ПОКА (п > начпоз) И (точек > 0) ВЫП
        ЧН();
        ЕСЛИ зн = "\" ТО
          послпалка:=п+1;
          УМЕНЬШИТЬ(точек)
        КОН
      КОН;
      п:=послпалка;
                                           (* пропуск лишних имён *)
      ПОКА (ч < дл) И (зв # "\") ВЫП
        ЧВ()
      КОН
    АЕСЛИ зв = "\" ТО
      ЧП()
    ИНАЧЕ                                  (* пропуск имён *)
      ПОКА (ч < дл) И (зв # "\") ВЫП
        ЧП()
      КОН
    КОН
  КОН;
                                           (* отсекаем лишнее *)
  ЕСЛИ п < дл ТО
    имя[п]:=0X
  КОН
КОН ИсправитьМесто;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       НайтиМесто-(
                    отместа-,
                       путь-,
                      место+:ЦЕПЬ
                  );
(*
 * Находит местоположение файла <место>, зная путь <путь> из точки <отместа>.
 *)
УКАЗ
  ЕСЛИ
       оЦепи.ПозицияЗнака(":",путь,0) # -1
  ТО                                                 (* путь - местоположение *)
    СПИСАТЬ(путь,место)
  ИНАЧЕ
    СПИСАТЬ(отместа,место);
    ЕСЛИ
           место # ""
    ТО
      ЕСЛИ
           место[ДЛИНА(место)-1] # "\"
      ТО
        оЦепи.ДобавитьВКонецЗнак(место,"\")
      КОН;
      ЕСЛИ
           (путь # "")
          И
           ((путь[0]="\")
          ИЛИ
           (путь[0]="/"))
      ТО                                             (* путь - корневой *)
        место[оЦепи.ПозицияЗнака(":",место,0)+1]:=0X
                                                     (* оставляем у старого места только накопитель *)
      КОН
    КОН;
    оЦепи.ДобавитьВКонец(место,путь)
  КОН;
  ИсправитьМесто(место)
КОН НайтиМесто;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       РазобратьИмя-(
                      пимя-,
                      путь+,
                       имя+,
                       тип+:ЦЕПЬ
                    );
(*
 * Переписывает из цепочки с полным именем файла <пимя> в <путь> путь к файлу,
 * в <имя> имя файла без его типа, в <тип> тип файла.
 *)
ПЕР
  пам:Файл.ВПолного;
  поз:ЦЕЛ;
  естьпуть,естьтип:КЛЮЧ;

 (*.................................подЗадача..*)
  ЗАДАЧА ТочечныйПуть(поз:ЦЕЛ):КЛЮЧ;
 (*-- Возвращает ВКЛ, если текущая "." определяет путь, а не тип файла --*)
  УКАЗ
    УМЕНЬШИТЬ(поз);
    ЕСЛИ
         (поз < 0)
        ИЛИ
         (пам[поз] = "\")
        ИЛИ
         (пам[поз] = ":")
        ИЛИ
         (пам[поз] = ".")
    ТО
      ВОЗВРАТ ВКЛ
    КОН;
      ВОЗВРАТ ОТКЛ
  КОН ТочечныйПуть;

УКАЗ
  СПИСАТЬ(пимя,пам);
  ИсправитьИмя(пам);
  путь[0]:=0X;
  имя[0]:=0X;
  тип[0]:=0X;

  естьпуть:=ОТКЛ;
  естьтип:=ОТКЛ;

       поз:=ДЛИНА(пам);
  ПОКА
       поз > 0
  ВЫП
    УМЕНЬШИТЬ(поз);
    ЕСЛИ
        пам[поз] = "."
    ТО
      ЕСЛИ
           НЕ естьпуть
         И
           (пам[поз+1] = 0X)
      ТО
        естьпуть:=ТочечныйПуть(поз)
      КОН;
      ЕСЛИ
           НЕ естьпуть
         И
           НЕ естьтип
      ТО
        естьтип:=ВКЛ;
        оЦепи.Часть(пам,тип,поз,Файл.длТипа-1);
        пам[поз]:=0X
      КОН
    АЕСЛИ
       (пам[поз] = "\") И НЕ естьпуть
    ТО
      естьпуть:=ВКЛ;
      оЦепи.Часть(пам,имя,поз+1,Файл.длИмени-1);
        пам[поз+1]:=0X
    КОН
  КОН;
  ЕСЛИ
       естьпуть
  ТО
    оЦепи.Часть(пам,путь,0,Файл.длПути-1)
  ИНАЧЕ
    оЦепи.Часть(пам,имя,0,Файл.длИмени-1)
  КОН
КОН РазобратьИмя;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       СобратьИмя-(
                    пимя+,
                    путь-,
                     имя-,
                     тип- :ЦЕПЬ
                  );
(*
 * Собирает полное имя файла <пимя> из пути к файлу <путь>,
 * имени файла без его типа <имя> и типа файла <тип>.
 *)
УКАЗ
  СПИСАТЬ(путь,пимя);
  ЕСЛИ
       пимя # ""
  ТО
       ИсправитьИмя(пимя);
    ЕСЛИ
         пимя[ДЛИНА(пимя)-1] # "\"
    ТО
      оЦепи.ДобавитьВКонецЗнак(пимя,"\")
    КОН
  КОН;
      оЦепи.ДобавитьВКонец(пимя,имя);
  ЕСЛИ
       тип # ""
  ТО
    ЕСЛИ
         тип[0] # "."
    ТО
      оЦепи.ДобавитьВКонецЗнак(пимя,".")
    КОН;
      оЦепи.ДобавитьВКонец(пимя,тип)
  КОН
КОН СобратьИмя;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ПутьИзПолного-(
                       пимя-,
                       путь+ :ЦЕПЬ
                     );
(*
 * Переписывает из цепочки с полным именем файла <пимя> в цепочку <путь>
 * путь к файлу (включая указание диска и "\" перед именем файла).
 *)
ПЕР
  пам:Файл.ВПолного;
УКАЗ
  Файл.РазобратьИмя(пимя,путь,пам,пам)
КОН ПутьИзПолного;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ИмяИзПолного-(
                       пимя-,
                        имя+ :ЦЕПЬ
                    );
(*
 * Переписывает из цепочки с полным именем файла <пимя> в цепочку <имя>
 * имя файла.
 *)
ПЕР
  пам:Файл.ВПолного;
УКАЗ
  Файл.РазобратьИмя(пимя,пам,имя,пам)
КОН ИмяИзПолного;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ИмяТипИзПолного-(
                           пимя-,
                         имятип+ :ЦЕПЬ
                       );
(*
 * Переписывает из цепочки с полным именем файла <пимя> в цепочку <имятип>
 * имя и тип (расширение) файла.
 *)
ПЕР
  пам:Файл.ВПолного;
  имя:Файл.ВИмени;
  тип:Файл.ВТипа;
УКАЗ
  Файл.РазобратьИмя(пимя,пам,имя,тип);
          СПИСАТЬ(имя,имятип);
 оЦепи.ДобавитьВКонец(имятип,тип)
КОН ИмяТипИзПолного;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ТипИзПолного-(
                      пимя-,
                       тип+ :ЦЕПЬ
                    );
(*
 * Переписывает из цепочки с полным именем файла <пимя> в цепочку <тип>
 * тип (расширение) файла.
 *)
ПЕР
  пам:Файл.ВПолного;
УКАЗ
  Файл.РазобратьИмя(пимя,пам,пам,тип)
КОН ТипИзПолного;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ИзменитьТип-(
                     пимя+,
                      тип- :ЦЕПЬ
                   );
(*
 * Изменяет тип (расширение) в полном имени файла <пимя> на <тип>.
 *)
ПЕР
       путь:Файл.ВПути;
       имя :Файл.ВИмени;
  старыйтип:Файл.ВТипа;
УКАЗ
  Файл.РазобратьИмя(пимя,путь,имя,старыйтип);
    Файл.СобратьИмя(пимя,путь,имя,тип)
КОН ИзменитьТип;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Существует-(имя-:ЦЕПЬ):КЛЮЧ;
(*
 * Возвращает ВКЛ, если существует файл с именем <имя>.
 *)
ПЕР
  поиск:Файл.нПоиск;
УКАЗ
  ЕСЛИ
       ОС.ПервыйПоискФ(имя,поиск)
  ТО
     ОС.ОкончитьПоискФ(поиск);
    ВОЗВРАТ ВКЛ
  КОН;
    ВОЗВРАТ ОТКЛ
КОН Существует;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ВремяИзменения-(
                          имя-:ЦЕПЬ;
                        время+:Файл.шцВремя
                      );
(*
 * Возвращает <время> изменения файла <имя> или -1.
 *)
ПЕР
  поиск:Файл.нПоиск;
УКАЗ
  ЕСЛИ
       НЕ ОС.ПервыйПоискФ(имя,поиск)
  ТО
    время:=-1;
    ВОЗВРАТ
  КОН;
    время:=поиск.времяПослЗаписи;

  ОС.ОкончитьПоискФ(поиск)

КОН ВремяИзменения;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Размер-(имя-:ЦЕПЬ):ЦЕЛ;
(*
 * Возвращает размер файла <имя> или -1.
 *)
ПЕР
  поиск:Файл.нПоиск;
  размер:ЦЕЛ;
УКАЗ
  ЕСЛИ
       НЕ ОС.ПервыйПоискФ(имя,поиск)
  ТО
    ВОЗВРАТ -1
  КОН;
  размер:=поиск.размерМладш;
 
          ОС.ОкончитьПоискФ(поиск);

  ВОЗВРАТ размер
КОН Размер;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Найти-(
                     имя-,
                     тип-,
                    пути-,
                    пимя+ :ЦЕПЬ
             ):КЛЮЧ;
(*
 * Ищет файл с именем <имя> и типом <тип> в списке путей нахождения файла
 * <пути>. Пути нахождения файла перечислены в цепочке <пути> через точку
 * с запятой. Если файл найден, то в цепочку <пимя> задача записывает полный
 * путь к этому файлу и возвращает ВКЛ, в противном случае возвращает ОТКЛ.
 *)
ПЕР
  путь:Файл.ВПути;
  начПути,
  конПути,дл_путей:ЦЕЛ;
УКАЗ
          дл_путей:=ДЛИНА(пути);

         начПути:=0;
  ПОВТОРЯТЬ
         конПути:=оЦепи.ПозицияЗнака(";",пути,начПути);
    ЕСЛИ
         конПути < 0
    ТО
         конПути:=дл_путей
    КОН;
    оЦепи.Часть(пути,путь,начПути,конПути-начПути);

         Файл.СобратьИмя(пимя,путь,имя,тип);
    ЕСЛИ
         Файл.Существует(пимя)
    ТО
      ВОЗВРАТ ВКЛ
    КОН;
    начПути:=конПути+1
  ДО начПути >= дл_путей;

      ВОЗВРАТ ОТКЛ
КОН Найти;

КОН Файл.
