home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / utilities / dirutils / visualshell / src / subs.c < prev    next >
C/C++ Source or Header  |  1992-10-28  |  33KB  |  1,101 lines

  1.         /*********************************
  2.          *                               *
  3.          *   Visual Shell v1.17  10/92   *
  4.          *                               *
  5.          *     by Torsten Jürgeleit      *
  6.          *                               *
  7.          *        subroutine part        *
  8.          *                               *
  9.          *********************************/
  10.  
  11.     /* Includes */
  12.  
  13. #include "includes.h"
  14. #include "imports.h"
  15. #include "protos.h"
  16.  
  17.     /* Lock given name with disabled system requesters */
  18.  
  19.    BPTR
  20. quiet_lock(BYTE *name, LONG mode)
  21. {
  22.    BPTR lock;
  23.    APTR old_window, *ptr = &((struct Process *)main_task)->pr_WindowPtr;
  24.  
  25.    old_window = *ptr;
  26.    *ptr       = (APTR)-1L;
  27.    lock       = Lock(name, mode);
  28.    *ptr       = old_window;
  29.    return(lock);
  30. }
  31.     /* Examine given lock with disabled system requesters */
  32.  
  33.    SHORT
  34. quiet_examine(BPTR lock, struct FileInfoBlock  *fib)
  35. {
  36.    APTR old_window, *ptr = &((struct Process *)main_task)->pr_WindowPtr;
  37.    SHORT error;
  38.  
  39.    old_window = *ptr;
  40.    *ptr       = (APTR)-1L;
  41.    if (Examine(lock, fib) == DOSFALSE) {
  42.       error = VSH_ERROR_EXAMINE_FAILED;
  43.    } else {
  44.       error = VSH_STATUS_NORMAL;
  45.    }
  46.    *ptr = old_window;
  47.    return(error);
  48. }
  49.     /* Check given path name for directory */
  50.  
  51.    SHORT
  52. check_for_dir(BYTE *dir_name)
  53. {
  54.    BPTR  lock;
  55.    SHORT error;
  56.  
  57.    if (!(lock = quiet_lock(dir_name, (LONG)SHARED_LOCK))) {
  58.       error = VSH_ERROR_DIR_NOT_FOUND;
  59.    } else {
  60.       if (Examine(lock, fib) == DOSFALSE) {
  61.      error = VSH_ERROR_EXAMINE_FAILED;
  62.       } else {
  63.      if (fib->fib_DirEntryType < 0) {
  64.         error = VSH_ERROR_NO_DIR;
  65.      } else {
  66.         error = VSH_STATUS_NORMAL;
  67.      }
  68.       }
  69.       UnLock(lock);
  70.    }
  71.    return(error);
  72. }
  73.     /* Check a file for a load file */
  74.  
  75.    SHORT
  76. check_for_load_file(BYTE *file_name)
  77. {
  78.    BPTR  lock, fh;
  79.    ULONG data;
  80.    SHORT error = VSH_STATUS_NORMAL;
  81.  
  82.    if (!(lock = quiet_lock(file_name, (LONG)SHARED_LOCK))) {
  83.       error = VSH_ERROR_LOCK_FAILED;
  84.    } else {
  85.       if (Examine(lock, fib) == DOSFALSE) {
  86.      error = VSH_ERROR_EXAMINE_FAILED;
  87.       } else {
  88.  
  89.      /* Check execute protection */
  90.      if (fib->fib_Protection & FIBF_EXECUTE) {
  91.         error = VSH_ERROR_EXECUTE_PROTECTED;
  92.      } else {
  93.  
  94.         /* Open file and read first long word */
  95.         if (!(fh = Open(file_name, (LONG)MODE_OLDFILE))) {
  96.            error = VSH_ERROR_OPEN_FAILED;
  97.         } else {
  98.            if (Read(fh, (BYTE *)&data, 4L) != 4) {
  99.           error = VSH_ERROR_READ_FAILED;
  100.            } else {
  101.  
  102.           /* Check for file header hunk */
  103.           if (data != 0x03f3) {
  104.              error = VSH_ERROR_NO_LOAD_FILE;
  105.           }
  106.            }
  107.            Close(fh);
  108.         }
  109.      }
  110.       }
  111.       UnLock(lock);
  112.    }
  113.    return(get_dos_error(error));
  114. }
  115.     /* Read new directory for specified filerequester */
  116.  
  117.    SHORT
  118. read_new_dir(struct FileRequest *freq, BYTE *dir_name, USHORT mode)
  119. {
  120.    SHORT error;
  121.  
  122.    print_status(VSH_STATUS_READ_DIR);
  123.    if (mode != READ_DIR_MODE_NO_OUTPUT) {
  124.       hcomp_freq_cursor(freq);
  125.       print_info_line(INFO_LINE_MODE_EMPTY);
  126.       print_fkey_text(FKEY_MODE_NONE);
  127.    }
  128.    if (! dir_name) {
  129.       dir_name = &freq->fr_DirName[0];
  130.    }
  131.    if ((error = new_dir(freq, dir_name)) == VSH_STATUS_NORMAL) {
  132.       if ((error = read_dir(freq)) == VSH_STATUS_NORMAL) {
  133.      if ((error = get_dir_info(freq)) == VSH_STATUS_NORMAL && freq ==
  134.                            &file_req[active_freq]) {   /* active file req ? */
  135.         if (mode != READ_DIR_MODE_NO_CD) {
  136.            error = change_current_dir();
  137.         }
  138.      }
  139.       }
  140.    }
  141.    print_dir_name(freq, NULL);
  142.    refresh_dir_info(freq);
  143.    if (mode == READ_DIR_MODE_NORMAL || mode == READ_DIR_MODE_NO_CD ||
  144.        (mode == READ_DIR_MODE_NO_PRINT && error != VSH_STATUS_NORMAL)) {
  145.       print_freq_lines(freq, freq->fr_Display.d_FirstVisibleNode, (USHORT)0,
  146.                        freq->fr_Display.d_VisibleLines);
  147.       hcomp_freq_cursor(freq);
  148.       print_info_line(INFO_LINE_MODE_NORMAL);
  149.       change_fkey_text();
  150.    }
  151.    return(error);
  152. }
  153.     /* Read the same directory once again */
  154.  
  155.    SHORT
  156. read_same_dir(struct FileRequest *freq, USHORT mode)
  157. {
  158.    struct FileNode  *fnode;
  159.    struct MinList   *old_file_list;
  160.    ULONG old_marked_entries, old_node_pos;
  161.    BYTE  *old_node_name = &file1_buffer[0];
  162.    SHORT old_cursor_line, error = VSH_STATUS_NORMAL;
  163.  
  164.    if (freq->fr_DirName[0] != '\0') {   /* dir name != "" ? */
  165.       old_marked_entries      = freq->fr_MarkedEntries;
  166.       old_file_list           = freq->fr_Display.d_List;
  167.       freq->fr_Display.d_List = NULL;
  168.       if (mode != READ_SAME_DIR_MODE_NO_CURSOR) {
  169.      if ((old_cursor_line = freq->fr_CursorLine) != -1) {
  170.         fnode        = get_file_node_under_cursor(freq);
  171.         old_node_pos = fnode->fn_Pos;
  172.         strncpy(old_node_name, &fnode->fn_Text[0], (size_t)
  173.                              fnode->fn_NameLen);
  174.         *(old_node_name + fnode->fn_NameLen) = '\0';
  175.      }
  176.       }
  177.       if ((error = read_new_dir(freq, NULL, (mode ==
  178.             READ_SAME_DIR_MODE_NORMAL ? READ_DIR_MODE_NO_PRINT :
  179.               READ_DIR_MODE_NO_OUTPUT))) == VSH_STATUS_NORMAL) {
  180.      duplicate_marks(freq, old_file_list, old_marked_entries);
  181.      if (mode != READ_SAME_DIR_MODE_NO_CURSOR) {
  182.         duplicate_cursor_line(freq, old_node_name, old_node_pos,
  183.                                old_cursor_line);
  184.      }
  185.          free_list(old_file_list, (ULONG)sizeof(struct FileNode));
  186.      print_freq_lines(freq, freq->fr_Display.d_FirstVisibleNode,
  187.                 (USHORT)0, freq->fr_Display.d_VisibleLines);
  188.      if (mode == READ_SAME_DIR_MODE_NORMAL) {
  189.         hcomp_freq_cursor(freq);
  190.         print_info_line(INFO_LINE_MODE_NORMAL);
  191.         change_fkey_text();
  192.      }
  193.       }
  194.    }
  195.    return(error);
  196. }
  197.     /* Enter new directory */
  198.  
  199.    SHORT
  200. new_dir(struct FileRequest *freq, BYTE *dir_name)
  201. {
  202.    struct MinList  *file_list;
  203.    BPTR  dir_lock;
  204.    SHORT error;
  205.  
  206.    if (!(dir_lock = quiet_lock(dir_name, (LONG)SHARED_LOCK))) {
  207.       error = VSH_ERROR_DIR_NOT_FOUND;
  208.    } else {
  209.       dir_name = &path1_buffer[0];
  210.       if ((error = build_path_name_from_lock(dir_name, dir_lock)) ==
  211.                             VSH_STATUS_NORMAL) {
  212.      if (Examine(dir_lock, fib) == DOSFALSE) {
  213.         error = VSH_ERROR_EXAMINE_FAILED;
  214.      } else {
  215.         if (fib->fib_DirEntryType < 0) {
  216.            error = VSH_ERROR_NO_DIR;
  217.         } else {
  218.            if (!(file_list = (struct MinList *)AllocMem((LONG)
  219.                sizeof(struct MinList), MEMF_PUBLIC | MEMF_CLEAR))) {
  220.           error = VSH_ERROR_OUT_OF_MEM;
  221.            } else {
  222.           NewList((struct List *)file_list);
  223.           free_dir(freq);
  224.           strcpy(&freq->fr_DirName[0], dir_name);
  225.           freq->fr_Display.d_List = file_list;
  226.           freq->fr_DirLock        = dir_lock;
  227.           CopyMem((BYTE *)&fib->fib_Date, (BYTE *)
  228.                     &freq->fr_Info.i_LastChanged, (LONG)
  229.                           sizeof(struct DateStamp));
  230.           return(VSH_STATUS_NORMAL);
  231.            }
  232.         }
  233.      }
  234.       }
  235.       UnLock(dir_lock);
  236.    }
  237.    return(error);
  238. }
  239.     /* Build file list for specified filerequester */
  240.  
  241.    SHORT
  242. read_dir(struct FileRequest *freq)
  243. {
  244.    struct AnchorPath     *ap   = &freq->fr_AnchorPath;
  245.    struct FileInfoBlock  *info = &ap->ap_Info;
  246.    struct MinList        *list = freq->fr_Display.d_List;
  247.    struct FileNode       *fnode;
  248.    BPTR  cd_lock;
  249.    LONG  rc;
  250.    SHORT error = VSH_STATUS_NORMAL;
  251.  
  252.    cd_lock = CurrentDir(freq->fr_DirLock);
  253.    if (!(rc = FindFirst(&freq->fr_FilePattern[0], ap))) {
  254.       do {
  255.      if (!(fnode = build_file_node(info))) {
  256.         error = VSH_ERROR_OUT_OF_MEM;
  257.      } else {
  258.         insert_file_node(fnode, list);
  259.      }
  260.       } while (error == VSH_STATUS_NORMAL && !(rc = FindNext(ap)));
  261.    }
  262.    FreeAnchorChain(ap);
  263.    CurrentDir(cd_lock);
  264.    if (error == VSH_STATUS_NORMAL) {
  265.       if (rc != ERROR_NO_MORE_ENTRIES) {
  266.      error = VSH_ERROR_FINDFIRST_OR_FINDNEXT_FAILED;
  267.       } else {
  268.      if (freq->fr_Display.d_NumEntries = count_file_nodes(list)) {
  269.         freq->fr_Display.d_FirstVisibleNode = list->mlh_Head;
  270.         freq->fr_CursorLine                 = 0;
  271.      }
  272.       }
  273.    }
  274.    return(error);
  275. }
  276.     /* Get infos about directory */
  277.  
  278.    SHORT
  279. get_dir_info(struct FileRequest *freq)
  280. {
  281.    struct Info  *info = &freq->fr_Info;
  282.    SHORT error = VSH_STATUS_NORMAL;
  283.  
  284.    if (Info(freq->fr_DirLock, idata) == DOSFALSE) {
  285.       error = VSH_ERROR_INFO_FAILED;
  286.    } else {
  287.       info->i_Valid         = 1;   /* mark info data as valid */
  288.       info->i_NumSoftErrors = idata->id_NumSoftErrors;
  289.       info->i_DiskState     = idata->id_DiskState;
  290.       info->i_BytesPerBlock = idata->id_BytesPerBlock;
  291.       info->i_TotalSize     = idata->id_NumBlocks * idata->id_BytesPerBlock;
  292.       info->i_FreeSize      = info->i_TotalSize - idata->id_NumBlocksUsed
  293.                           * idata->id_BytesPerBlock;
  294.       BtoCStr(&info->i_VolumeName[0], ((struct DosList *)
  295.         BTOC(idata->id_VolumeNode))->dol_Name, (LONG)MAX_FILE_NAME_LEN);
  296.       sum_file_sizes(freq);
  297.    }
  298.    return(error);
  299. }
  300.     /* Free file list for specified filerequester */
  301.  
  302.    VOID
  303. free_dir(struct FileRequest *freq)
  304. {
  305.    if (freq->fr_DirLock) {
  306.       UnLock(freq->fr_DirLock);
  307.       freq->fr_DirLock = NULL;
  308.    }
  309.    free_list(freq->fr_Display.d_List, (LONG)sizeof(struct FileNode));
  310.    freq->fr_Display.d_List = NULL;
  311.    free_list(freq->fr_SaveFileList, (LONG)sizeof(struct FileNode));
  312.    freq->fr_SaveFileList               = NULL;
  313.    freq->fr_DirName[0]                 = '\0';
  314.    freq->fr_Info.i_Valid               = 0;   /* mark info data as invalid */
  315.    freq->fr_Display.d_NumEntries       = 0;
  316.    freq->fr_SaveNumEntries             = 0;
  317.    freq->fr_Display.d_FirstVisibleNode = NULL;
  318.    freq->fr_SaveFirstVisibleNode       = NULL;
  319.    freq->fr_CursorLine                 = -1;
  320.    freq->fr_SaveCursorLine             = -1;
  321.    freq->fr_MarkedEntries              = 0;
  322.    freq->fr_SaveMarkedEntries          = 0;
  323.    freq->fr_MarkedSize                 = 0;
  324.    freq->fr_SaveMarkedSize             = 0;
  325.    freq->fr_Mode                       = FREQ_MODE_NORMAL;
  326. }
  327.     /* Free the complete list and the list header */
  328.  
  329.    VOID
  330. free_list(struct MinList *list, ULONG size)
  331. {
  332.    struct Node  *node;
  333.    BOOL path_flag = FALSE;
  334.  
  335.    if (list && size) {
  336.       if (size == sizeof(struct FileNode)) {
  337.      path_flag = TRUE;   /* free path buffer - allocated by Find */
  338.       }
  339.       while (node = RemHead((struct List *)list)) {
  340.      if (path_flag == TRUE) {
  341.         DosFreeMem(((struct FileNode *)node)->fn_Path);
  342.      }
  343.      FreeMem(node, size);
  344.       }
  345.       FreeMem(list, (LONG)sizeof(struct MinList));
  346.    }
  347. }
  348.     /* Build full path name from given lock */
  349.  
  350.    SHORT
  351. build_path_name_from_lock(BYTE *buffer, BPTR lock)
  352. {
  353.    BYTE  temp[MAX_PATH_NAME_LEN + 1];
  354.    SHORT error;
  355.  
  356.    if (!PathName(lock, &temp[0], (LONG)MAX_PATH_NAME_LEN / FSIZE)) {
  357.       error = VSH_ERROR_NO_PATH_NAME;
  358.    } else {
  359.       if ((error = build_device_name(buffer, lock)) == VSH_STATUS_NORMAL) {
  360.      strcat(buffer, strchr(&temp[0], (USHORT)':') + 1);
  361.       }
  362.    }
  363.    return(error);
  364. }
  365.     /* Build full path name from given file node */
  366.  
  367.    VOID
  368. build_path_name_from_file_node(BYTE *buffer, struct FileRequest  *freq,
  369.                             struct FileNode  *fnode)
  370. {
  371.    if (freq->fr_Mode == FREQ_MODE_FIND) {
  372.       strcpy(buffer, fnode->fn_Path);
  373.    } else {
  374.       strcpy(buffer, &freq->fr_DirName[0]);
  375.    }
  376.    append_base_name(buffer, fnode);
  377. }
  378.     /* Build full path name from path relative to current directory */
  379.  
  380.    SHORT
  381. build_path_name_from_relative_path(BYTE *buffer, BYTE *path)
  382. {
  383.    BPTR  lock;
  384.    SHORT error;
  385.  
  386.    if (!(lock = quiet_lock(path, (LONG)SHARED_LOCK))) {
  387.       error = VSH_ERROR_LOCK_FAILED;
  388.    } else {
  389.       error = build_path_name_from_lock(buffer, lock);
  390.       UnLock(lock);
  391.    }
  392.    return(error);
  393. }
  394.     /* Append full path of specified entry at given pointer */
  395.  
  396.    BYTE *
  397. append_path_name(BYTE *buffer, struct FileRequest *freq,
  398.                     struct FileNode *fnode, USHORT mode)
  399. {
  400.    BPTR lock;
  401.    BYTE *ptr;
  402.  
  403.    if (mode == APPEND_MODE_QUOTED) {
  404.       *buffer++ = '"';
  405.    }
  406.    if (freq->fr_Mode == FREQ_MODE_FIND) {
  407.       strcpy(buffer, fnode->fn_Path);
  408.    } else {
  409.       strcpy(buffer, &freq->fr_DirName[0]);
  410.    }
  411.    ptr = append_base_name(buffer, fnode);
  412.    if (!(lock = quiet_lock(buffer, (LONG)SHARED_LOCK))) {
  413.       ptr = NULL;
  414.    } else {
  415.       if (mode == APPEND_MODE_QUOTED) {
  416.      *ptr++ = '"';
  417.      *ptr   = '\0';
  418.       }
  419.       UnLock(lock);
  420.    }
  421.    return(ptr);
  422. }
  423.     /* Append base name of specified entry at given pointer */
  424.  
  425.    BYTE *
  426. append_base_name(BYTE *buffer, struct FileNode *fnode)
  427. {
  428.    BYTE c;
  429.  
  430.    buffer += strlen(buffer);
  431.    c    = *(buffer - 1);
  432.    if (c != ':' && c != '/') {
  433.       *buffer++ = '/';
  434.    }
  435.    strncpy(buffer, &fnode->fn_Text[0], (size_t)fnode->fn_NameLen);
  436.    *(buffer += fnode->fn_NameLen) = '\0';
  437.    return(buffer);
  438. }
  439.     /* Build device name for given lock */
  440.  
  441.    SHORT
  442. build_device_name(BYTE *buffer, BPTR lock)
  443. {
  444.    struct DevInfo  *dvi;
  445.    struct Task     *task;
  446.    SHORT error = VSH_ERROR_NO_PATH_NAME;
  447.  
  448.    /* First get ptr to file system task the lock belongs to */
  449.    if (!lock) {   /* ZERO lock -> boot device */
  450.       task = (struct Task *)_parent_proc->pr_FileSystemTask;
  451.    } else {
  452.       task = (struct Task *)((struct FileLock *)BTOC(lock))->fl_Task;
  453.    }
  454.  
  455.    /* Search device with this file system task in AmigaDOS device list */
  456.    Forbid();
  457.    for (dvi = (struct DevInfo *)GetDevInfo(NULL); dvi;
  458.                         dvi = BTOC(dvi->dvi_Next)) {
  459.       if (dvi->dvi_Type == DLT_DEVICE && (struct Task *)dvi->dvi_Task ==
  460.                             task && dvi->dvi_Name) {
  461.      /* Convert device name to C string and append ':' */
  462.      BtoCStr(buffer, dvi->dvi_Name, (LONG)MAX_FILE_NAME_LEN);
  463.      buffer   += strlen(buffer);
  464.      *buffer++ = ':';
  465.      *buffer   = '\0';
  466.      error     = VSH_STATUS_NORMAL;
  467.      break;
  468.       }
  469.    }
  470.    Permit();
  471.    return(error);
  472. }
  473.     /* Build device list for specified filerequester */
  474.  
  475.    SHORT
  476. read_devs(struct FileRequest *freq)
  477. {
  478.    struct DevInfo   *dvi = NULL;
  479.    struct MinList   *list;
  480.    struct FileNode  *fnode;
  481.    BPTR  lock;
  482.    BYTE  *path = &path2_buffer[0];
  483.    BOOL  ram_flag = FALSE;
  484.    SHORT error = VSH_STATUS_NORMAL;
  485.  
  486.    print_status(VSH_STATUS_READ_DEVS);
  487.    print_fkey_text(FKEY_MODE_NONE);
  488.    freq->fr_Display.d_List             = NULL;
  489.    freq->fr_Display.d_NumEntries       = 0;
  490.    freq->fr_Display.d_FirstVisibleNode = NULL;
  491.    freq->fr_CursorLine                 = -1;
  492.    freq->fr_Mode                       = FREQ_MODE_DEVS_ASN;
  493.    if (!(list = (struct MinList *)AllocMem((LONG)
  494.                sizeof(struct MinList), MEMF_PUBLIC | MEMF_CLEAR))) {
  495.       error = VSH_ERROR_OUT_OF_MEM;
  496.    } else {
  497.       NewList((struct List *)list);
  498.       freq->fr_Display.d_List = list;
  499.       while (dvi = (struct DevInfo *)GetDevInfo((struct DeviceList *)dvi)) {
  500.      switch (dvi->dvi_Type) {
  501.         case DLT_DEVICE :
  502.            if (dvi->dvi_Task && dvi->dvi_Name) {
  503.           if (!(fnode = build_dev_node(dvi))) {
  504.              return(VSH_ERROR_OUT_OF_MEM);
  505.           } else {
  506.              if (! strncmp(&fnode->fn_Text[0], "RAM:", 4L)) {
  507.             ram_flag = TRUE;
  508.              }
  509.              insert_file_node(fnode, list);
  510.           }
  511.            }
  512.            break;
  513.         case DLT_VOLUME :
  514.            if (dvi->dvi_Task && dvi->dvi_Name) {
  515.           if (!(fnode = build_dev_node(dvi))) {
  516.              return(VSH_ERROR_OUT_OF_MEM);
  517.           } else {
  518.              insert_file_node(fnode, list);
  519.           }
  520.            }
  521.            break;
  522.         case DLT_DIRECTORY :
  523.            BtoCStr(path, dvi->dvi_Name, (LONG)MAX_PATH_NAME_LEN);
  524.            strcat(path, (BYTE *)":");
  525.            if (lock = quiet_lock(path, (LONG)SHARED_LOCK)) {
  526.           if (Examine(lock, fib) == DOSTRUE) {
  527.              if (fib->fib_DirEntryType > 0) {   /* dir ? */
  528.             if (!(fnode = build_dev_node(dvi))) {
  529.                UnLock(lock);
  530.                return(VSH_ERROR_OUT_OF_MEM);
  531.             } else {
  532.                insert_file_node(fnode, list);
  533.             }
  534.              }
  535.           }
  536.           UnLock(lock);
  537.            }
  538.            break;
  539.      }
  540.       }
  541.       if (ram_flag == FALSE) {
  542.      if (!(fnode = build_dev_node(NULL))) {
  543.         return(VSH_ERROR_OUT_OF_MEM);
  544.      } else {
  545.         insert_file_node(fnode, list);
  546.      }
  547.       }
  548.       if (freq->fr_Display.d_NumEntries = count_file_nodes(list)) {
  549.      freq->fr_Display.d_FirstVisibleNode = list->mlh_Head;
  550.      freq->fr_CursorLine                 = 0;
  551.       }
  552.    }
  553.    return(error);
  554. }
  555.     /* Get file node under cursor of specified filerequester */
  556.  
  557.    struct FileNode *
  558. get_file_node_under_cursor(struct FileRequest *freq)
  559. {
  560.    struct FileNode  *fnode = NULL;
  561.    SHORT i, cursor_line = freq->fr_CursorLine;
  562.  
  563.    if (cursor_line != -1) {
  564.       fnode = (struct FileNode *)freq->fr_Display.d_FirstVisibleNode;
  565.       for (i = cursor_line; i; i--) {
  566.      fnode = (struct FileNode *)fnode->fn_Node.mln_Succ;
  567.       }
  568.    }
  569.    return(fnode);
  570. }
  571.     /* Remove file node from file list of specified filerequester */
  572.  
  573.    struct FileNode *
  574. remove_file_node(struct FileRequest *freq, struct FileNode *fnode)
  575. {
  576.    struct FileNode  *next_fnode;
  577.    struct MinNode   *fv_node = freq->fr_Display.d_FirstVisibleNode;
  578.    USHORT vlines = freq->fr_Display.d_VisibleLines;
  579.    ULONG  num_entries = freq->fr_Display.d_NumEntries,
  580.       fv_pos = ((struct FileNode *)fv_node)->fn_Pos, pos = fnode->fn_Pos;
  581.  
  582.    if (pos == fv_pos) {   /* change first visible node */
  583.       if (pos > 1 && (num_entries - pos) < vlines) {
  584.      fv_node = fv_node->mln_Pred;
  585.       } else {
  586.      fv_node = fv_node->mln_Succ;
  587.       }
  588.    } else {
  589.       if (num_entries > vlines && pos > fv_pos && fv_pos == (num_entries -
  590.                                   vlines + 1)) {
  591.      fv_node = fv_node->mln_Pred;
  592.       }
  593.    }
  594.    freq->fr_Display.d_FirstVisibleNode = fv_node;
  595.    freq->fr_Display.d_NumEntries       = recount_file_nodes(fnode);
  596.    if (fnode->fn_Type == ENTRY_TYPE_DIR) {   /* dir ? */
  597.       freq->fr_Info.i_Dirs--;
  598.    } else {
  599.       freq->fr_Info.i_FileSizes -= fnode->fn_Size;
  600.       freq->fr_Info.i_Files--;
  601.    }
  602.    next_fnode = (struct FileNode *)fnode->fn_Node.mln_Succ;
  603.    Remove((struct Node *)fnode);
  604.    FreeMem(fnode, (LONG)sizeof(struct FileNode));
  605.    print_freq_lines(freq, fv_node, (USHORT)0, vlines);
  606.    refresh_dir_info(freq);
  607.    return(next_fnode);
  608. }
  609.     /* Rename file node from file list of specified filerequester */
  610.  
  611.    VOID
  612. rename_file_node(struct FileRequest *freq, struct FileNode *fnode,
  613.                                  BYTE *name)
  614. {
  615.    struct MinList  *flist = freq->fr_Display.d_List;
  616.    struct MinNode  *fv_node = freq->fr_Display.d_FirstVisibleNode;
  617.    BYTE   c, *ptr = &fnode->fn_Text[0];
  618.    USHORT i, vlines = freq->fr_Display.d_VisibleLines;
  619.    ULONG  num_entries = freq->fr_Display.d_NumEntries,
  620.       fv_pos = ((struct FileNode *)fv_node)->fn_Pos,
  621.       old_pos = fnode->fn_Pos, new_pos;
  622.  
  623.    Remove((struct Node *)fnode);
  624.    for (i = 0; i < MAX_FILE_NAME_LEN; i++) {   /* insert new fnode name */
  625.       if (!(c = *name++)) {
  626.      break;
  627.       } else {
  628.      *ptr++ = c;
  629.       }
  630.    }
  631.    fnode->fn_NameLen = i;
  632.    for ( ; i < MAX_FILE_NAME_LEN; i++) {   /* clear rest of file name */
  633.       *ptr++ = ' ';
  634.    }
  635.    insert_file_node(fnode, flist);
  636.    if ((new_pos = fnode->fn_Pos) != old_pos) {   /* position changed ? */
  637.       if (old_pos == fv_pos) {   /* change first visible node */
  638.      if (old_pos > 1 && (num_entries - old_pos) < vlines) {
  639.         fv_pos = old_pos - 1;
  640.      } else {
  641.         fv_pos = old_pos + 1;
  642.      }
  643.      fv_node = get_list_node(flist, num_entries, fv_pos);
  644.       } else {
  645.      fv_pos = ((struct FileNode *)fv_node)->fn_Pos;
  646.      if (new_pos < fv_pos && (num_entries - fv_pos) < vlines) {
  647.         fv_node = fv_node->mln_Pred;
  648.      }
  649.       }
  650.    }
  651.    freq->fr_Display.d_FirstVisibleNode = fv_node;
  652.    freq->fr_Display.d_NumEntries       = count_file_nodes(flist);
  653.    print_freq_lines(freq, fv_node, (USHORT)0, vlines);
  654. }
  655.     /* Duplicate file list from one filerequester to another one */
  656.  
  657.    SHORT
  658. duplicate_file_list(struct FileRequest *freq1, struct FileRequest *freq2)
  659. {
  660.    struct FileNode  *fnode1, *fnode2;
  661.    struct MinList   *flist1, *flist2;
  662.    BPTR  dir_lock;
  663.    ULONG num_entries, marked_entries, marked_size;
  664.    SHORT error = VSH_STATUS_NORMAL;
  665.  
  666.    if (!(dir_lock = DupLock(freq1->fr_DirLock))) {
  667.       error = VSH_ERROR_OUT_OF_MEM;
  668.    } else {
  669.       if (!(flist2 = (struct MinList *)AllocMem((LONG)
  670.                     sizeof(struct MinList), MEMF_PUBLIC))) {
  671.      error = VSH_ERROR_OUT_OF_MEM;
  672.       } else {
  673.      NewList((struct List *)flist2);
  674.      if (freq1->fr_Mode == FREQ_MODE_DEVS_ASN || freq1->fr_Mode ==
  675.                                FREQ_MODE_FIND) {
  676.         flist1         = freq1->fr_SaveFileList;
  677.         num_entries    = freq1->fr_SaveNumEntries;
  678.         marked_entries = freq1->fr_SaveMarkedEntries;
  679.         marked_size    = freq1->fr_SaveMarkedSize;
  680.      } else {
  681.         flist1         = freq1->fr_Display.d_List;
  682.         num_entries    = freq1->fr_Display.d_NumEntries;
  683.         marked_entries = freq1->fr_MarkedEntries;
  684.         marked_size    = freq1->fr_MarkedSize;
  685.      }
  686.      fnode1 = (struct FileNode *)flist1->mlh_Head;
  687.      while (fnode1->fn_Node.mln_Succ && error == VSH_STATUS_NORMAL) {
  688.         if (!(fnode2 = (struct FileNode *)AllocMem((LONG)
  689.               sizeof(struct FileNode), MEMF_PUBLIC | MEMF_CLEAR))) {
  690.            error = VSH_ERROR_OUT_OF_MEM;
  691.         } else {
  692.            strcpy(&fnode2->fn_Text[0], &fnode1->fn_Text[0]);   /* copy file node */
  693.            CopyMem((BYTE *)fnode1, (BYTE *)fnode2, (LONG)
  694.                            sizeof(struct FileNode));
  695.            AddTail((struct List *)flist2, (struct Node *)fnode2);
  696.            fnode1 = (struct FileNode *)fnode1->fn_Node.mln_Succ;
  697.         }
  698.      }
  699.      if (error == VSH_STATUS_NORMAL) {
  700.         free_dir(freq2);
  701.         strcpy(&freq2->fr_DirName[0], &freq1->fr_DirName[0]);
  702.         freq2->fr_DirLock                    = dir_lock;
  703.         freq2->fr_Display.d_List             = flist2;
  704.         freq2->fr_Display.d_NumEntries       = num_entries;
  705.         freq2->fr_Display.d_FirstVisibleNode = flist2->mlh_Head;
  706.         if (num_entries) {
  707.            freq2->fr_CursorLine = 0;
  708.         } else {
  709.            freq2->fr_CursorLine = -1;
  710.         }
  711.         freq2->fr_MarkedEntries = marked_entries;
  712.         freq2->fr_MarkedSize    = marked_size;
  713.         CopyMem((BYTE *)&freq1->fr_Info, (BYTE *)&freq2->fr_Info,
  714.                          (LONG)sizeof(struct Info));
  715.         return(VSH_STATUS_NORMAL);
  716.      }
  717.      free_list(flist2, (LONG)sizeof(struct FileNode));
  718.      FreeMem(flist2, (LONG)sizeof(struct MinList));
  719.       }
  720.       UnLock(dir_lock);
  721.    }
  722.    return(error);
  723. }
  724.     /* Duplicate marks from one file list to another */
  725.  
  726.    VOID
  727. duplicate_marks(struct FileRequest *freq, struct MinList *old_file_list,
  728.                            ULONG old_marked_entries)
  729. {
  730.    struct FileNode  *fnode, *old_fnode = (struct FileNode *)
  731.                              old_file_list->mlh_Head,
  732.             *new_fnode = (struct FileNode *)
  733.                       freq->fr_Display.d_List->mlh_Head;
  734.    if (old_marked_entries) {
  735.       while (old_fnode->fn_Node.mln_Succ) {
  736.      if (old_fnode->fn_Marked) {
  737.         if (fnode = search_file_node(new_fnode, &old_fnode->fn_Text[0],
  738.                            old_fnode->fn_NameLen)) {
  739.            fnode->fn_Marked     = 1;
  740.            freq->fr_MarkedSize += fnode->fn_Size;
  741.            freq->fr_MarkedEntries++;
  742.            new_fnode = fnode;
  743.         }
  744.      }
  745.      old_fnode = (struct FileNode *)old_fnode->fn_Node.mln_Succ;
  746.       }
  747.    }
  748. }
  749.     /* Duplicate cursor position from one filerequester to another */
  750.  
  751.    VOID
  752. duplicate_cursor_line(struct FileRequest *freq, BYTE *old_name,
  753.                        ULONG old_pos, SHORT old_cursor_line)
  754. {
  755.    struct FileNode  *fnode;
  756.  
  757.    if (old_cursor_line != -1) {
  758.       if (!(fnode = search_file_node((struct FileNode *)
  759.                freq->fr_Display.d_List->mlh_Head, old_name, (USHORT)
  760.                                strlen(old_name)))) {
  761.      fnode = (struct FileNode *)get_list_node(freq->fr_Display.d_List,
  762.                     freq->fr_Display.d_NumEntries, old_pos);
  763.       }
  764.       move_freq_cursor(freq, fnode, MOVE_MODE_NO_OUTPUT);
  765.    }
  766. }
  767.     /* Restore old cursor position for given filerequester */
  768.  
  769.    VOID
  770. restore_old_cursor_line(struct FileRequest *freq, BYTE *old_name,
  771.                        ULONG old_pos, SHORT old_cursor_line)
  772. {
  773.    struct FileNode  *fnode;
  774.  
  775.    if (old_cursor_line == -1 || !freq->fr_Display.d_NumEntries) {
  776.       freq->fr_CursorLine = -1;
  777.       print_info_line(INFO_LINE_MODE_EMPTY);
  778.    } else {
  779.       if (!(fnode = search_file_node((struct FileNode *)
  780.                freq->fr_Display.d_List->mlh_Head, old_name, (USHORT)
  781.                                strlen(old_name)))) {
  782.      fnode = (struct FileNode *)get_list_node(freq->fr_Display.d_List,
  783.                     freq->fr_Display.d_NumEntries, old_pos);
  784.       }
  785.       move_freq_cursor(freq, fnode, MOVE_MODE_NO_HCOMP);
  786.    }
  787. }
  788.     /* Jump to an specified entry in file requester */
  789.  
  790.    VOID
  791. jump_to_freq_entry(BYTE *name, USHORT mode)
  792. {
  793.    struct FileRequest  *freq = &file_req[active_freq];
  794.    struct FileNode     *fnode;
  795.  
  796.    if (mode == JUMP_MODE_FIRST) {
  797.       fnode = search_file_node((struct FileNode *)
  798.             freq->fr_Display.d_List->mlh_Head, name, (USHORT)0);
  799.    } else {
  800.       fnode = (struct FileNode *)
  801.              get_file_node_under_cursor(freq)->fn_Node.mln_Succ;
  802.  
  803.       /* End of list ? */
  804.       if (fnode->fn_Node.mln_Succ) {
  805.      if (!(fnode = search_file_node(fnode, name, (USHORT)0))) {
  806.         fnode = search_file_node((struct FileNode *)
  807.             freq->fr_Display.d_List->mlh_Head, name, (USHORT)0);
  808.      }
  809.       } else {
  810.      fnode = search_file_node((struct FileNode *)
  811.             freq->fr_Display.d_List->mlh_Head, name, (USHORT)0);
  812.       }
  813.    }
  814.    move_freq_cursor(freq, fnode, MOVE_MODE_NORMAL);
  815. }
  816.     /* Move cursor to specified entry in file requester */
  817.  
  818.    VOID
  819. move_freq_cursor(struct FileRequest *freq, struct FileNode *fnode,
  820.                                     USHORT mode)
  821. {
  822.    ULONG  cursor_line, num_entries = freq->fr_Display.d_NumEntries;
  823.    USHORT i, vlines = freq->fr_Display.d_VisibleLines,
  824.       vlines_half = vlines >> 1;
  825.  
  826.    if (mode == MOVE_MODE_NORMAL) {
  827.       hcomp_freq_cursor(freq);
  828.       print_info_line(INFO_LINE_MODE_EMPTY);
  829.    }
  830.    if (fnode) {
  831.       cursor_line = fnode->fn_Pos - 1;
  832.       if (num_entries > vlines) {
  833.      if (cursor_line < vlines_half) {
  834.         fnode = (struct FileNode *)freq->fr_Display.d_List->mlh_Head;
  835.      } else {
  836.         if (cursor_line >= (num_entries - vlines_half)) {
  837.            fnode = (struct FileNode *)
  838.                       freq->fr_Display.d_List->mlh_TailPred;
  839.            i = vlines - 1;
  840.         } else {
  841.            i = vlines_half - (!(vlines & 1) ? 1 : 0);   /* dec for even num of visible lines */
  842.         }
  843.         for ( ; i; i--) {
  844.            fnode = (struct FileNode *)fnode->fn_Node.mln_Pred;
  845.         }
  846.         cursor_line -= fnode->fn_Pos - 1;
  847.      }
  848.       } else {
  849.      fnode = (struct FileNode *)freq->fr_Display.d_List->mlh_Head;
  850.  
  851.       }
  852.    } else {
  853.       if (freq->fr_DirLock && freq->fr_Display.d_NumEntries) {
  854.          fnode = (struct FileNode *)freq->fr_Display.d_List->mlh_Head;
  855.      cursor_line = 0;
  856.       } else {
  857.      cursor_line = -1;
  858.       }
  859.    }
  860.    if (!fnode || fnode != (struct FileNode *)
  861.                       freq->fr_Display.d_FirstVisibleNode) {
  862.       freq->fr_Display.d_FirstVisibleNode = (struct MinNode *)fnode;
  863.       if (mode != MOVE_MODE_NO_OUTPUT) {
  864.      print_freq_lines(freq, (struct MinNode *)fnode, (USHORT)0, vlines);
  865.       }
  866.    } else {
  867.       if (mode == MOVE_MODE_PRINT) {
  868.      print_freq_lines(freq, freq->fr_Display.d_FirstVisibleNode,
  869.                              (USHORT)0, vlines);
  870.       }
  871.    }
  872.    freq->fr_CursorLine = cursor_line;
  873.    if (mode != MOVE_MODE_NO_OUTPUT && mode != MOVE_MODE_NO_CURSOR) {
  874.       hcomp_freq_cursor(freq);
  875.       print_info_line(INFO_LINE_MODE_NORMAL);
  876.    }
  877. }
  878.     /* Check last changed date of directory for given file requester */
  879.  
  880.    SHORT
  881. check_date_stamp(struct FileRequest *freq, USHORT mode)
  882. {
  883.    struct DateStamp  *old_date = &freq->fr_Info.i_LastChanged,
  884.              *new_date = &fib->fib_Date;
  885.    SHORT error = VSH_STATUS_NORMAL;
  886.  
  887.    if (freq->fr_Mode == FREQ_MODE_NORMAL && freq->fr_DirName[0] != '\0') {
  888.       if ((error = quiet_examine(freq->fr_DirLock, fib)) ==
  889.                             VSH_STATUS_NORMAL) {
  890.      if (old_date->ds_Days != new_date->ds_Days || old_date->ds_Minute
  891.                  != new_date->ds_Minute || old_date->ds_Tick
  892.                              != new_date->ds_Tick) {
  893.         if (mode == READ_SAME_DIR_MODE_NO_READ) {
  894.            error = VSH_STATUS_READ_DIR;   /* indicate to read same dir again */
  895.         } else {
  896.            error = read_same_dir(freq, mode);
  897.         }
  898.      }
  899.       }
  900.    }
  901.    return(error);
  902. }
  903.     /* Set last changed date of directory for given file requester */
  904.  
  905.    SHORT
  906. set_date_stamp(struct FileRequest *freq)
  907. {
  908.    SHORT error;
  909.  
  910.    if ((error = quiet_examine(freq->fr_DirLock, fib)) == VSH_STATUS_NORMAL) {
  911.       CopyMem((BYTE *)&fib->fib_Date, (BYTE *)&freq->fr_Info.i_LastChanged,
  912.                         (LONG)sizeof(struct DateStamp));
  913.    }
  914.    return(error);
  915. }
  916.     /* Execute program with arguments */
  917.  
  918.    SHORT
  919. execute(BYTE *prog, BYTE *args)
  920. {
  921.    BYTE  cmd[MAX_DIR_NAME_LEN + MAX_FILE_NAME_LEN + 1], *ptr = &cmd[0];
  922.    SHORT error;
  923.  
  924.    if (wshell_flag && FindPort("REXX") && *(USHORT *)((UBYTE *)DOSBase -
  925.                                222)    == 0x4ef9) {
  926.       *ptr++ = '[';   /* needed for WShell + ARexx + patched Execute() vector */
  927.    }
  928.    *ptr++ = '"';
  929.    strcpy(ptr, prog);
  930.    ptr   += strlen(prog);
  931.    *ptr++ = '"';
  932.    *ptr++ = ' ';
  933.    strcpy(ptr, args);
  934.    if (Execute(&cmd[0], nil_handle, Output()) == DOSFALSE) {
  935.       error = VSH_ERROR_EXECUTE_FAILED;
  936.    } else {
  937.       error = VSH_STATUS_NORMAL;
  938.    }
  939. /*
  940. Printf("Execute(%s)=%d\n", &cmd[0], error);
  941. */
  942.    return(error);
  943. }
  944.     /* Find files or dirs by pattern, start from path in active freq */
  945.  
  946.    SHORT
  947. find(struct FileRequest *freq, BYTE *pattern)
  948. {
  949.    struct AnchorPath     *ap;
  950.    struct FileInfoBlock  *info;
  951.    struct MinList        *list;
  952.    struct FileNode       *fnode;
  953.    BYTE  *path, *path_buffer, *buffer;
  954.    LONG  rc;
  955.    BPTR  cd_lock;
  956.    BOOL  keepon = TRUE;
  957.    SHORT error = VSH_STATUS_NORMAL;
  958.  
  959.    print_fkey_text(FKEY_MODE_NONE);
  960.    freq->fr_Display.d_NumEntries       = 0;
  961.    freq->fr_Display.d_FirstVisibleNode = NULL;
  962.    freq->fr_CursorLine                 = -1;
  963.    freq->fr_MarkedEntries              = 0;
  964.    freq->fr_MarkedSize                 = 0;
  965.    freq->fr_Mode                       = FREQ_MODE_FIND;
  966.    if (!(list = (struct MinList *)AllocMem((LONG)sizeof(struct MinList),
  967.                            MEMF_PUBLIC | MEMF_CLEAR))) {
  968.       error = VSH_ERROR_OUT_OF_MEM;
  969.    } else {
  970.       NewList((struct List *)list);
  971.       freq->fr_Display.d_List = list;
  972.       if (!(ap = (struct AnchorPath *)AllocMem((LONG)
  973.                  (sizeof(struct AnchorPath) + MAX_DIR_NAME_LEN +
  974.                MAX_FILE_NAME_LEN + 1), MEMF_PUBLIC | MEMF_CLEAR))) {
  975.      error = VSH_ERROR_OUT_OF_MEM;
  976.       } else {
  977.      ap->ap_BreakBits = SIGBREAKF_CTRL_C;
  978.      ap->ap_StrLen    = MAX_DIR_NAME_LEN + MAX_FILE_NAME_LEN;
  979.      ap->ap_Flags     = APF_DoWild;   /* traverse through ALL dirs */
  980.      info             = &ap->ap_Info;
  981.      path             = &ap->ap_Buf[0];
  982.      PreParse(pattern, &line1_buffer[0]);
  983.      pattern = &line1_buffer[0];   /* compiled pattern */
  984.      buffer  = &path1_buffer[0];
  985.      cd_lock = CurrentDir(freq->fr_DirLock);
  986.      enable_abort = 1;
  987.      if (!(rc = FindFirst(star, ap))) {
  988.         do {
  989.  
  990.            /* Check if entry matches pattern */
  991.            if ((info->fib_DirEntryType < 0 || (info->fib_DirEntryType > 0
  992.                      && !(ap->ap_Flags & APF_DidDir))) &&
  993.                 PatternMatch(pattern, &info->fib_FileName[0]) ==
  994.                                      TRUE) {
  995.           /* Build full path name and display it in status line */
  996.           if ((error = build_path_name_from_relative_path(buffer,
  997.                           path)) != VSH_STATUS_NORMAL) {
  998.              keepon = FALSE;
  999.           } else {
  1000.              print_dos_status(DOS_MODE_FIND, buffer, NULL);
  1001.  
  1002.              /* Strip file name from path and build file node from it */
  1003.              *(BaseName(buffer) - 1) = '\0';
  1004.              if (!(path_buffer = DosAllocMem((LONG)(strlen(buffer) +
  1005.                                      1)))) {
  1006.             keepon = FALSE;
  1007.             error  = VSH_ERROR_OUT_OF_MEM;
  1008.              } else {
  1009.             if (!(fnode = build_file_node(info))) {
  1010.                keepon = FALSE;
  1011.                error  = VSH_ERROR_OUT_OF_MEM;
  1012.             } else {
  1013.                strcpy(path_buffer, buffer);
  1014.                fnode->fn_Path = path_buffer;
  1015.                insert_file_node(fnode, list);
  1016.             }
  1017.              }
  1018.           }
  1019.            }
  1020.  
  1021.            /* If directory then check if already scanned */
  1022.            if (info->fib_DirEntryType > 0) {
  1023.           if (ap->ap_Flags & APF_DidDir) {
  1024.              ap->ap_Flags &= ~APF_DidDir;   /* don't enter dir again */
  1025.           } else {
  1026.              ap->ap_Flags |= APF_DoDir;   /* enter dir */
  1027.           }
  1028.            }
  1029.         } while (keepon == TRUE && !(rc = FindNext(ap)));
  1030.      }
  1031.      enable_abort = 0;
  1032.      FreeAnchorChain(ap);
  1033.      CurrentDir(cd_lock);
  1034.      if (error == VSH_STATUS_NORMAL) {
  1035.         switch (rc) {
  1036.            case ERROR_BREAK :
  1037.           error = VSH_ERROR_ABORTED;
  1038.            case ERROR_NO_MORE_ENTRIES :
  1039.           if (freq->fr_Display.d_NumEntries =
  1040.                            count_file_nodes(list)) {
  1041.              freq->fr_Display.d_FirstVisibleNode = list->mlh_Head;
  1042.              freq->fr_CursorLine                 = 0;
  1043.           }
  1044.           break;
  1045.            default :
  1046.           error = VSH_ERROR_FINDFIRST_OR_FINDNEXT_FAILED;
  1047.           break;
  1048.         }
  1049.      }
  1050.      FreeMem(ap, (LONG)(sizeof(struct AnchorPath) + MAX_DIR_NAME_LEN +
  1051.                             MAX_FILE_NAME_LEN + 1));
  1052.       }
  1053.    }
  1054.    return(error);
  1055. }
  1056.     /* Clear console read buffer */
  1057.  
  1058.    VOID
  1059. clear_input_line(VOID)
  1060. {
  1061.    if ((struct CommandLineInterface *)BADDR(_parent_proc->pr_CLI) ==
  1062.                                  save_cli) {   /* no EndCLI ? */
  1063.       dos_packet(con_input_fhandle->fh_Type, (LONG)ACTION_FLUSH);
  1064.    }
  1065. }
  1066.     /* Force string into command line */
  1067.  
  1068.    SHORT
  1069. force_string(BYTE *string, USHORT len, USHORT mode)
  1070. {
  1071.    BYTE  *path = &path2_buffer[0];
  1072.    SHORT error = VSH_STATUS_NORMAL;
  1073.  
  1074.    if ((struct CommandLineInterface *)BADDR(_parent_proc->pr_CLI) ==
  1075.                                  save_cli) {   /* no EndCLI ? */
  1076.  
  1077.       if (mode == FORCE_MODE_NEWLINE_APPEND || mode ==
  1078.                           FORCE_MODE_NEWLINE_COPY) {
  1079.      if (dos_packet(con_input_fhandle->fh_Type, (LONG)ACTION_FLUSH) ==
  1080.                                  DOSFALSE) {
  1081.         error = VSH_ERROR_WRONG_CONMAN_VERSION;
  1082.      } else {
  1083.         if (mode == FORCE_MODE_NEWLINE_APPEND) {
  1084.            *(string + len++) = '\n';   /* append new line char */
  1085.         } else {
  1086.            strncpy(path, string, (size_t)len);   /* copy string with new line char */
  1087.            *(path + len++) = (BYTE)'\n';
  1088.            string          = path;
  1089.         }
  1090.      }
  1091.       }
  1092.       if (error == VSH_STATUS_NORMAL) {
  1093.      if (dos_packet(con_input_fhandle->fh_Type, CONMAN_ACTION_FORCE,
  1094.             con_input_fhandle, string, (LONG)len) == DOSFALSE) {
  1095.         error = VSH_ERROR_WRONG_CONMAN_VERSION;
  1096.      }
  1097.       }
  1098.    }
  1099.    return(error);
  1100. }
  1101.