|
Поиск подстрок в файлах
Во всех файлах выбранного каталога приложение ищет шаблон/фразу (с использованием простейшего конечного автомата) и выводит список смещений(от нуля), по которым в файле находится шаблон.
Пример. Шаблон "123". Текст в файле: "123_45634gain51235" . Смещения: 0, 14
Шаблон задается в отдельном файле pattern.txt в каталоге с приложением. Это для того, чтобы можно было задать любую кодировку.
То есть ищется последовательность байтов, из которых состоит шаблон/фраза.
Память выделяется под целый файл (любого размера).
Недостатки:
-
При обработке файлов память 'выделяется и освобождается' для каждого файла вместо того, чтобы выделить один раз под самый большой файл и освободить после обработки всех файлов.
-
Не работает с длинными путями. Максимальный путь файла - 260 символов.
-
Небольшие утечки памяти(?). Примеры: А. после запуска приложения оно занимает 0.7 Мб после завершения процесса поиска в каталоге с 91355(штук) файлами общим размером 74 Гб приложение занимает 10 Мб. То есть утечка 9 Мб.
Б. Обработка двух файлов по 4.94 Гб. размер занятой памяти 1 Мб. утечка 0.3 Мб
Незначительно.
-
Нет шкалы хода процесса.
скачать 26_findSubStr_gui 64 bit
скачать 26_findSubStr_gui_32bit
32-битная версия работает с файлами до 4 Гб, но ещё нужно вычесть память, занимаемую операционной системой.
При попытке прочитать большой файл в поле на форме будет выведено сообщение и приложение продолжит обрабатывать следующие файлы.
! Если 32-битная версия в 64-битной ОС будет завершаться с ошибкой (Имя сбойного модуля: ntdll.dll), то установите какой-нибудь режим совместимости.
Выбор кодировки (текстовый редактор)
/* 26_findSubStr_gui.c */
//cd "C:\Program Files\mingw-w64\x86_64-8.1.0-win32-seh-rt_v6-rev0\mingw64\bin"
//x86_64-w64-mingw32-gcc.exe 26_findSubStr_gui.c 26_list_intr.c 26_findSubStr_impl.c -lole32 -luuid -o 26_findSubStr_gui.exe -mwindows
// 26_findSubStr_gui.exe
//cd "C:\Program Files (x86)\mingw-w64\i686-8.1.0-win32-dwarf-rt_v6-rev0\mingw32\bin"
//i686-w64-mingw32-gcc.exe 26_findSubStr_gui.c 26_list_intr.c 26_findSubStr_impl.c -lole32 -luuid -o 26_findSubStr_gui_32bit.exe -mwindows
// 26_findSubStr_gui_32bit.exe
//где-то устанавливается значение NTDDI_VERSION, равное NTDDI_WS03. Из-за этого в shobjidl.h не выполняется
//секция ( условие #if NTDDI_VERSION >= NTDDI_VISTA) ), где "определяется" IID_IFileOpenDialog.
#define NTDDI_VERSION 0x06000000 //NTDDI_VISTA or NTDDI_WIN6
#include <shobjidl.h>
#include <windows.h>
#include <shlwapi.h>
#include <stdio.h>
#include "26_list_intr.h"
#include <string.h>
#include <stdlib.h>
#include <stdint.h> // для int64_t
#include <inttypes.h> // для правильного вывода int64_t в printf
#include "26_findSubStr_impl.h"
#define message01 L"Список файлов в каталоге: \xD\xA"
#define message02 L"Каталог не выбран."
#define message03 L"В каталоге нет файлов."
#define message04 L"ошибка при открытии файла "
#define message05 L"ошибка при получении данных из файла "
#define message06 L"ошибка при создании таблицы состояний конечного автомата"
#define message07 L"ошибка при поиске шаблона в файле "
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void startFind(void);
void OutPathToEditW(Paths * ps, wchar_t * cstr);
void OutPathToFileW(Paths * ps, wchar_t * cstr, FILE * ff);
void ShowDialogDirSelect(PWSTR selectedFilePath);
void AddTextToEditW(wchar_t * str);
HWND hWnd_button1, editctl;
WCHAR selectedFilePath[MAX_PATH+1];
HWND hMainWnd; // дескриптор будущего окна
Paths exPath;
WORD sx, sy;
/* 64-bit */
long long id_button1 = 10001;
long long IDC_EDIT = 10002;
/* // 32-bit
int id_button1 = 10001;
int IDC_EDIT = 10002;
*/
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
wchar_t szClassName[] = L"26_findSubStr_gui"; // строка с именем класса
MSG msg; // создаём экземпляр структуры MSG для обработки сообщений
WNDCLASSEXW wc; // создааём экземпляр, для обращения к членам класса WNDCLASSEX
// TCHAR type depends from the UNICODE preprocessor constant
/////////////////
wc.cbSize = sizeof(wc); // размер структуры (в байтах)
wc.style = CS_HREDRAW | CS_VREDRAW; // стиль класса окна
wc.lpfnWndProc = WndProc; // указатель на пользовательскую функцию
wc.lpszMenuName = NULL; // указатель на имя меню (у нас его нет)
wc.lpszClassName = szClassName; // указатель на имя класса
wc.cbWndExtra = 0; // число освобождаемых байтов в конце структуры
wc.cbClsExtra = 0; // число освобождаемых байтов при создании экземпляра приложения
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // декриптор пиктограммы
wc.hIconSm = LoadIcon(NULL, IDI_WINLOGO); // дескриптор маленькой пиктограммы (в трэе)
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // дескриптор курсора
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // дескриптор кисти для закраски фона окна
wc.hInstance = hInst; // указатель на строку, содержащую имя меню, применяемого для класса
if(!RegisterClassExW(&wc)){
// в случае отсутствия регистрации класса:
MessageBoxW(NULL, L"Класс окна не зарегистрирован!", L"Err_Err", MB_OK);
return 1;
}
// Функция, создающая окно:
hMainWnd = CreateWindowW(
szClassName, // имя класса
L"Поиск строки в файлах", // заголовок окна // L"\x41F\x43E\x438\x441\x43A \x441\x442\x440\x43E\x43A\x438 \x432 \x444\x430\x439\x43B\x430\x445"
WS_OVERLAPPEDWINDOW, // | WS_VSCROLL, // режимы отображения окна
CW_USEDEFAULT, // позиция окна по оси х
CW_USEDEFAULT, // позиция окна по оси у (раз дефолт в х, то писать не нужно)
500, // ширина окна
400, // высота окна (раз дефолт в ширине, то писать не нужно)
NULL, // дескриптор родительского окна
NULL, // дескриптор меню
hInst, // дескриптор экземпляра приложения
NULL); // ничего не передааём из WndProc
if(!hMainWnd){
// в случае некорректного создания окна (неверные параметры и тп):
MessageBoxW(NULL, L"Главное окно не создано!", L"Err_Err2", MB_OK);
return 0;
}
//////////////button1 - to start coping. //////////////////////////////////
//Создаем кнопку
//macro TEXT(L"Выбрать каталог...")
hWnd_button1 = CreateWindowW(L"button", L"Выбрать каталог и начать поиск...", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 30, 250, 30, hMainWnd, (HMENU)id_button1, hInst, NULL);
////////////// EDIT 1/////////////////////////////////////////
editctl = CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_HSCROLL |
ES_LEFT | ES_AUTOHSCROLL | ES_WANTRETURN | ES_MULTILINE | ES_AUTOVSCROLL | ES_NOHIDESEL,
10, 70, 100, 100, hMainWnd, (HMENU)IDC_EDIT, hInst, 0);
ShowWindow(hMainWnd, nCmdShow); // отображаем окно
UpdateWindow(hMainWnd); // обновляем окно
while(GetMessageW(&msg, NULL, 0, 0)){ // извлекаем сообщения из очереди, посылаемые фу-циями, ОС
TranslateMessage(&msg); // интерпретируем сообщения
DispatchMessageW(&msg); // передааём сообщения обратно ОС
}
return msg.wParam; // возвращаем код выхода из приложения
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
switch(uMsg){
case WM_COMMAND:
if (LOWORD(wParam) == id_button1){ // start coping
startFind();
}
break;
case WM_SIZE: // Sent to a window after its size has changed
sx = LOWORD(lParam); //ширина клиентской области
sy = HIWORD(lParam); //высота
SetWindowPos(editctl, (HWND)NULL, 10, 70, sx- 20, sy - 80, 0);
break;
case WM_DESTROY:
PostQuitMessage(0); // отправляем WinMain() сообщение WM_QUIT
break;
default:
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
}
void startFind(void){
int readRes;
Node * nextEx;
int64_t * nextState = NULL;
int64_t m;
int64_t * arr_out;
int64_t n_out, i;
uint8_t rez;
int64_t _file_size = 0;
char * pattern = NULL;
char * textF = NULL;
wchar_t * offsetsText = NULL;
wchar_t itemOffsetsText[25];
int64_t SizeOfoffsetsText = 0, SizeOfoffsetsTextNew;
unsigned int s;
int64_t currPos = (int64_t)0;
SetWindowTextW(editctl, L"### Начало\xD\xA");
if ( ! ( rez = getTextW(L"pattern.txt", &pattern, &m) ) ){ // ok
rez = createNextState(pattern, &nextState, m);
free(pattern);
if (rez == 1){
AddTextToEditW(message06);
AddTextToEditW(L"\xD\xA");
return;
}
} else {
if ( rez == 2 ){
AddTextToEditW(message04);
AddTextToEditW(L"pattern.txt");
AddTextToEditW(L"\xD\xA");
}else if( rez == 1) {
AddTextToEditW(message05);
AddTextToEditW(L"pattern.txt");
AddTextToEditW(L"\xD\xA");
} else {
AddTextToEditW(L"Файл pattern.txt пустой.");
AddTextToEditW(L"\xD\xA");
}
return;
}
selectedFilePath[0] = L'\0';
ShowDialogDirSelect(selectedFilePath);
if( selectedFilePath[0] == L'\0' ){
AddTextToEditW(message02);
AddTextToEditW(L"\xD\xA");
if ( nextState != NULL )
free(nextState);
return;
}
initList(&exPath);
readRes = ReadPaths(&exPath, selectedFilePath);
if ( exPath.nump > 0 ){
//OutPathToEditW(&exPath, message01); //shows all paths
nextEx = exPath.begin;
while ( nextEx != NULL ){
if ( ! ( rez = getTextW( nextEx->item.path1 , &textF, &_file_size) ) ){ // "D:\\\\text.txt"
//printf(" _file_size == %" PRId64 "\n", _file_size);
rez = findSubStr(textF, _file_size, nextState, m, &n_out, &arr_out);
free(textF);
if (rez == 1){
AddTextToEditW(message07);
AddTextToEditW(nextEx->item.path1);
AddTextToEditW(L"\xD\xA");
nextEx = nextEx->next;
continue;
}
//обработка полученного массива смещений
if ( n_out != 0 ){
AddTextToEditW(nextEx->item.path1);
AddTextToEditW(L"\xD\xA");
// Int64.MaxValue = 9223372036854775807, учитывая это
// выделяю память для всех элементов массива в текстовом представлении.
// Если памяти, выделенной для предыдущей обработки, хватит для текущей, то
// использую её.
SizeOfoffsetsTextNew = (22 + 2) * sizeof(wchar_t) * n_out;
if ( offsetsText != NULL ){
if ( SizeOfoffsetsTextNew > SizeOfoffsetsText ){
free(offsetsText);
offsetsText = (wchar_t*) malloc( SizeOfoffsetsTextNew );
}
} else {
offsetsText = (wchar_t*) malloc( SizeOfoffsetsTextNew );
}
SizeOfoffsetsText = SizeOfoffsetsTextNew;
s = 0;
AddTextToEditW(L"Количество найденных вхождений: ");
swprintf(itemOffsetsText, 25, L"%I64d", n_out); //check return value
AddTextToEditW(itemOffsetsText);
AddTextToEditW(L"\xD\xA");
for( i = 0; i < n_out; i++ ){
swprintf(itemOffsetsText, 25, L"%I64d", arr_out[i]); //check return value
swprintf(offsetsText + s, SizeOfoffsetsText / sizeof(wchar_t) - s, L", %s", itemOffsetsText);
s += wcslen(itemOffsetsText) + 2; // + ", "
}
AddTextToEditW(offsetsText + 2); // skip ", "
AddTextToEditW(L"\xD\xA\xD\xA");
}
}else {
if ( rez == 2 ){
AddTextToEditW(message04);
AddTextToEditW(nextEx->item.path1);
AddTextToEditW(L"\xD\xA");
}else if ( rez == 1 ){
AddTextToEditW(message05);
AddTextToEditW(nextEx->item.path1);
AddTextToEditW(L"\xD\xA");
}
// rez == 3 - file is empty.
}
nextEx = nextEx->next;
}
if ( offsetsText != NULL)
free(offsetsText);
}
else{
AddTextToEditW(message03);
AddTextToEditW(L"\xD\xA");
}
//очистка памяти
freeList(&exPath);
if ( nextState != NULL )
free(nextState);
AddTextToEditW(L"### Конец.");
}
void OutPathToEditW(Paths * ps, wchar_t * cstr){
unsigned int slen, clen, i = 0, num;
Node * nextEx;
wchar_t * str;
//MessageBoxW(NULL, L"Отладка", L"Отладка", MB_OK);
slen = ( ps->lengthAllPaths1 + ps->nump * 2 ) * sizeof(wchar_t); // + \xD\xA
clen = wcslen(cstr) * sizeof(wchar_t);
num = clen + slen + 3*sizeof(wchar_t);
str = (wchar_t *) malloc( num ); // + \xD\xA + \0
if (str == NULL){
SetWindowTextW(editctl, L"Нет свободной памяти.");
return;
}
num = num / sizeof(wchar_t);
swprintf(str, num, L"%s\xD\xA", cstr); //check return value
i = wcslen(cstr) + 2;
nextEx = ps->begin;
while ( nextEx != NULL ){
swprintf(str + i, num - i, L"%s\xD\xA", nextEx->item.path1); //check return value
i += nextEx->item.num1 + 2; // + \xD\xA
nextEx = nextEx->next;
}
SetWindowTextW(editctl, str);
free(str);
}
void AddTextToEditW(wchar_t * str){
int nLen = GetWindowTextLengthW(editctl);
SendMessageW (editctl, EM_SETSEL, nLen, nLen);
SendMessageW (editctl, EM_REPLACESEL, 0, (LPARAM)str);
}
void OutPathToFileW(Paths * ps, wchar_t * cstr, FILE * ff){
Node * nextEx;
fputws(cstr, ff);
fputws(L"\n", ff);
nextEx = ps->begin;
while ( nextEx != NULL ){
fputws(nextEx->item.path1, ff);
fputws(L"\n", ff);
nextEx = nextEx->next;
}
}
void ShowDialogDirSelect(PWSTR selectedFilePath){
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
IFileOpenDialog *pFileOpen;
// Create the FileOpenDialog object.
hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_ALL, &IID_IFileOpenDialog, (void**)(&pFileOpen) );
if (SUCCEEDED(hr))
{
// options
hr = pFileOpen->lpVtbl->SetOptions(pFileOpen, FOS_PICKFOLDERS);
// Show the Open dialog box.
hr = pFileOpen->lpVtbl->Show(pFileOpen, NULL);
// Get the file name from the dialog box.
if (SUCCEEDED(hr))
{
IShellItem *pItem;
hr = pFileOpen->lpVtbl->GetResult(pFileOpen, &pItem);
if (SUCCEEDED(hr))
{
PWSTR pszFilePath;
hr = pItem->lpVtbl->GetDisplayName(pItem, SIGDN_FILESYSPATH, &pszFilePath);
// Display the file name to the user.
if (SUCCEEDED(hr))
{
wcscpy (selectedFilePath, pszFilePath);
//MessageBoxW(NULL, pszFilePath, L"File Path", MB_OK);
// winnt.h
//typedef wchar_t WCHAR;
//typedef WCHAR *NWPSTR,*LPWSTR,*PWSTR;
/* The size modifier of the string literal (L, u, U) determines the type of the literal.
char a[] = "Hello";
wchar_t b[] = L"Hello";
char16_t c[] = u"Hello";
char32_t d[] = U"Hello"; */
// null termination: L'\0'
// https://docs.microsoft.com/ru-ru/cpp/cpp/string-and-character-literals-cpp?view=vs-2019
// https://en.wikipedia.org/wiki/C_string_handling
CoTaskMemFree(pszFilePath);
}
pItem->lpVtbl->Release(pItem);
}
}
pFileOpen->lpVtbl->Release(pFileOpen);
}
CoUninitialize();
}
// https://docs.microsoft.com/en-us/windows/win32/learnwin32/example--the-open-dialog-box
}
/* 26_findSubStr_impl.h -- интерфейс */
#include <stdint.h> // для int64_t
#ifndef _FIND_SUB_STR_IMPL_
#define _FIND_SUB_STR_IMPL_
// создается таблица состояний автомата для Шаблона, которую можно использовать
// для поиска Шаблона в разных файлах.
//вход
// pattern - шаблон/фраза, который нужно искать
//
// выход
// nextState - указатель на двухмерный массив размером m * colNum
// colNum всегда равно 256
// m - максимальный номер состояния автомата, или длина шаблона
//
// возврат. 0 - хорошо. 1 - нет памяти
uint8_t createNextState(const char * pattern, int64_t ** nextState, int64_t m);
// Поиск подстроки в строке
// вход
// text - указатель на файл с данными(текстом), где нужно искать шаблон
// _file_size - длина файла
// nextState - указатель на уже созданную таблицу состояний
// m - максимальный номер состояния автомата( длина шаблона)
// выход
// n_out - количество найденных совпадений
// arr_out - указатель на массив смещений ( от 0 ) от начала text. Или null
//
// возврат 1, если возникли разные ошибки при работе функции (не связано с выделением памяти).
//
// переданные указатель на файл с текстом (массив данных). Кодировка не важна.
// передается готовая таблица состояний.
// формируется связный список, который заполняется смещениями.
// после окончания поиска создаётся массив и туда копируются все элементы связного списка.
//
uint8_t findSubStr(const char * text, int64_t _file_size, int64_t * nextState, int64_t m, int64_t * n_out, int64_t ** arr_out);
//открывает файл на чтение. Выделяет память под него.
//вход
// fname - имя файла
//выход
// str - данные файла
// _file_size - размер файла
// возврат. 0 - хорошо. 1 - нет памяти, другое ; 2 - ошибка при открытии файла; 3 - пустой файл
uint8_t getTextW(const wchar_t * fname, char ** str, int64_t * _file_size);
#endif
/* 26_findSubStr_impl.c -- реализация */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h> // для int64_t
#include <windows.h>
#include <inttypes.h> // для правильного вывода int64_t в printf
#include "26_findSubStr_impl.h"
#define colNum 256
typedef struct node {
int64_t value;
struct node * next;
} Node;
typedef struct list {
Node * head;
Node * current;
int64_t length;
} List;
static void initList(List * lst);
static void freeList(List * lst);
static uint8_t addToList(List * lst, int64_t value);
static uint8_t ListToArray(List * lst, int64_t ** arr_out);
uint8_t createNextState(const char * pattern, int64_t ** nextState, int64_t m){
char * Pk; //суффикс подстроки
int j;
int64_t PkLen, i, PKi, Pkinc, PKi2;
short int equal;
*nextState = malloc( sizeof(int64_t) * ( m +1) * colNum ); // 256 столбцов для всех значений из байта
if ( *nextState == NULL )
return 1;
Pk = malloc( m + 2 ); //
if ( Pk == NULL ){
free(*nextState);
*nextState = NULL;
return 1;
}
*Pk = '\0'; // ?
// I I I I I I I I I I формирование таблицы состояний I I I I I I I I I I
for ( i = 0; i <= m ; i++ ){
for ( j = 0; j <= colNum ; j++ ){ // for ( j = 0; j <= 127 ; j++ ){ //
//берем очередной возможный символ и присоединяем его справа к префиксу подстроки
if ( i > 0 ){
strncpy(Pk, pattern, i);
*(Pk+i) = (char)j;
*(Pk+i+1) = '\0';
PkLen = i + 1;
}else {
*(Pk) = (char)j;
*(Pk+1) = '\0';
PkLen = 1;
}
PKi = PkLen;
if ( PkLen > m ){
PKi = m;
}
again: PKi2 = PKi;
Pkinc = 1;
// проверяю, является Pi суффиксом Pk ?
while ( PKi2 > 0 ){ // сравнение последнего символа префикса подстроки и последнего символа суффикса прочитанного текста
if ( *(pattern + PKi2 - 1 ) != *( Pk + PkLen - Pkinc ) ){
break;
}
++Pkinc;
--PKi2;
}
if ( PKi2 > 0 ){ // String's parts are not equal.
--PKi;
if (PKi > 0)
goto again;
else
*( (*nextState) + i*colNum + j) = 0;
}else{
*( (*nextState) + i*colNum + j) = PKi;
}
}
}
free(Pk);
return 0;
}
uint8_t findSubStr(const char * text, int64_t _file_size, int64_t * nextState, int64_t m, int64_t * n_out, int64_t ** arr_out){
int64_t state = (int64_t)0;
int64_t i;
uint8_t rez;
List offsets;
initList(&offsets);
for ( i = (int64_t)0; i < _file_size; i++ ){
state = *( nextState + state*colNum + (unsigned char)*(text + i) );
if( state == m ){
if ( addToList(&offsets, i - m + 1) ){
freeList(&offsets);
return 1;
}
}
}
*n_out = offsets.length;
if ( *n_out > 0 ){
//создать массив и заполнить его смещениями из списка
rez = ListToArray(&offsets, arr_out);
freeList(&offsets);
if ( rez )
return rez;
}
return 0;
}
uint8_t getTextW(const wchar_t * fname, char ** str, int64_t * _file_size) {
LARGE_INTEGER u_winFsz;
DWORD nNumberOfBytesToRead; // typedef unsigned long DWORD;
DWORD NumberOfBytesRead;
int64_t currPos = (int64_t)0;
int64_t size;
HANDLE hFile;
hFile = CreateFileW(fname, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL , NULL); // | FILE_FLAG_OVERLAPPED
if(hFile == INVALID_HANDLE_VALUE){
*_file_size = -1;
return 2;
}
else{
GetFileSizeEx(hFile, &u_winFsz);
*_file_size = u_winFsz.QuadPart;
size = u_winFsz.QuadPart;
}
if ( *_file_size > (int64_t)0 ){
*(str) = malloc(*_file_size);
if ( *(str) == NULL ){
CloseHandle(hFile);
return 1;
}
do {
nNumberOfBytesToRead = (size > (unsigned __int64) ULONG_MAX) ? ULONG_MAX : (unsigned long)size; // 4294967295
if ( ReadFile(hFile, *(str) + currPos, nNumberOfBytesToRead, &NumberOfBytesRead, NULL) == 0 )
break;
size -= NumberOfBytesRead;
currPos += NumberOfBytesRead;
} while ( size > 0 && NumberOfBytesRead == nNumberOfBytesToRead);
CloseHandle(hFile);
hFile = NULL;
if ( size == 0 )
return 0;
else {
free(*(str));
return 1;
}
} else {
if ( hFile != NULL )
CloseHandle(hFile);
return 3;
}
}
static void initList(List * lst){
lst->head = NULL;
lst->current = NULL;
lst->length = (int64_t)0;
}
static void freeList(List * lst){
Node * c, * n;
c = lst->head;
while ( c != NULL ){
n = c->next;
free(c);
c = n;
}
}
static uint8_t addToList(List * lst, int64_t value){
Node * newNode;
newNode = malloc(sizeof(Node));
if ( newNode == NULL )
return 1;
newNode->next = NULL;
newNode->value = value;
if ( lst->head == NULL ){
lst->head = newNode;
lst->current = newNode;
(lst->length)++;
} else {
lst->current->next = newNode;
lst->current = newNode;
(lst->length)++;
}
return 0;
}
static uint8_t ListToArray(List * lst, int64_t ** arr_out){
int64_t il;
il = lst->length;
if ( il == 0 )
return 0;
Node * cn;
*arr_out = malloc( il * sizeof(int64_t) );
if ( *arr_out == NULL )
return 1;
cn = lst->head;
il = 0;
while ( cn != NULL ){
*( *arr_out + il) = cn->value;
il++;
cn = cn->next;
}
return 0;
}
/* list_intr.h -- интерфейс списка */
#ifndef _LIST_INTR_
#define _LIST_INTR_
////////////////////////////////////////
typedef struct item {
wchar_t * path1;
unsigned int num1;
} Item;
////////////////////////////////////////
typedef struct node {
Item item;
struct node * next;
} Node;
typedef struct paths{
Node * begin;
unsigned int nump;
unsigned int lengthAllPaths1; // длина путей всех файлов
} Paths;
//инициализирует переменные
void initList(Paths * exPath);
//чтение данных из настроечного файла
//вход: exPath - указатель на список, куда будут добавлены пути файлов
//выход: заполнен список exPath; возвращает 0 в случае успешного выполнения
int ReadPaths(Paths * exPath, wchar_t * path);
//очищает занятую память
int freeList(Paths * exPath);
#endif
/* файл list_intr.c - реализация интерфейса*/
#include <windows.h>
#include <shlwapi.h>
#include <stdio.h>
#include "26_list_intr.h"
#define f1 L"\\*.*"
static void findFAdd(wchar_t * path, HANDLE handleNext, WIN32_FIND_DATAW * dataF, Paths * exPath, Node ** nextExInFind);
void initList(Paths * exPath){
exPath->begin = NULL;
exPath->nump = 0;
exPath->lengthAllPaths1 = 0;
}
int ReadPaths(Paths * exPath, wchar_t * path){
int num, nb;
wchar_t * pathN;
WIN32_FIND_DATAW dataF;
HANDLE handleNext;
Node * nextEx = NULL;
nb = sizeof(wchar_t);
// sizeof(f1) = 10 ( not 8 )
num = sizeof(f1) + wcslen(path) * sizeof(wchar_t) + nb;
pathN = (wchar_t*) malloc( num );
if ( pathN == NULL )
return 3;
swprintf(pathN, num / nb, L"%s%s", path, f1); //check return value
handleNext = FindFirstFileW( pathN, &dataF); // => dataF.cFileName = "."
if ( handleNext != INVALID_HANDLE_VALUE ){
findFAdd( path, handleNext, &dataF, exPath, &nextEx);
FindClose(handleNext);
}
//else //можно обработать ошибку
free(pathN); // можно заменить выделение памяти под pathN на pathN[MAX_PATH]
return 0;
} // end ReadPaths()
// поиск вложенных файлов и добавление к основному списку существующих путей
static void findFAdd(wchar_t * path, HANDLE handleNext, WIN32_FIND_DATAW * dataF, Paths * exPath,
Node ** nextExInFind){
Node * tempNode;
int len, mem = 0;
wchar_t CurPath[MAX_PATH+1];
while ( FindNextFileW(handleNext, dataF) != 0 ){
if ( (dataF -> dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
swprintf(CurPath, MAX_PATH+1, L"%s\\%s", path, dataF -> cFileName); //check return value
tempNode = malloc(sizeof(Node));
if ( tempNode == NULL ){
return; // ВОЗВРАТ БЕЗ ОПОВЕЩЕНИЯ
}
tempNode->next = NULL;
len = wcslen(CurPath);
mem = (len + 1)* sizeof(wchar_t);
tempNode -> item.path1 = (wchar_t*) malloc ( mem ); // выделение памяти под путь
if ( tempNode -> item.path1 == NULL ){
return; // ВОЗВРАТ БЕЗ ОПОВЕЩЕНИЯ
}
wcscpy (tempNode -> item.path1, CurPath); // копирование можно заменить выделением памяти
tempNode -> item.num1 = len; // без /0
exPath->lengthAllPaths1 += len;
if ( exPath->begin == NULL ){ // добавляем первый элемент
exPath->begin = tempNode;
*nextExInFind = tempNode;
exPath->nump++;
} else { // добавляем последующие элементы
(*nextExInFind)->next = tempNode;
*nextExInFind = tempNode;
exPath->nump++;
}
} else {
if ( (dataF -> cFileName)[0] == L'.' && (dataF -> cFileName)[1] == L'.' ) // ".."
continue;
wchar_t newDirF[MAX_PATH+1];
_snwprintf(newDirF, MAX_PATH+1, L"%s\\%s", path, dataF -> cFileName);
wchar_t pathN[MAX_PATH+1];
_snwprintf(pathN, MAX_PATH+1, L"%s\\%s%s", path, dataF -> cFileName, f1);
HANDLE handleNext2 = FindFirstFileW( pathN, dataF); // => dataF.cFileName = "."
findFAdd(newDirF, handleNext2, dataF, exPath, nextExInFind);
FindClose(handleNext2);
}
}
}
int freeList(Paths * exPath){
Node * currN = NULL;
Node * nextN;
currN = exPath->begin;
while (currN != NULL){
nextN = currN-> next;
if (currN->item.path1 != NULL){
free(currN->item.path1);
}
free(currN);
currN = nextN;
}
exPath->nump = 0;
exPath->lengthAllPaths1 = 0;
}
51 + 23
|
|
Комментарии