Тотальная неудачница и убийца жёстких дисков.
#post-id: 2837-03-37
#original-date: 2.05.2008 Fri
#original-time: 3:37 AM
#original-day:  2837
#original-host: WinXP Prof SP2 (Build 2600)

Освоила функцию strtok() ^^ Когда в какой-то статье про QuickBasic был код, реализующий эту функцию на QB, я не могла понять, что она делает, а слово "токен" вообще меня вгоняло в ступор. Нынче оно попрежнему вгоняет меня в ступор, но теперь я понимаю принцип действия ^^

#include <string.h>
...
char *token&#59;
char *line = "LINE TO BE SEPARATED"&#59;
char *search = " "&#59;

/* Token will point to "LINE". */
token = strtok(line, search)&#59;

/* Token will point to "TO". */
token = strtok(NULL, search)&#59;



Это пример из Инета ^^ А вот что там было написано про другую версию функции:

The strtok_r() function is thread-safe and stores its state in a user-supplied buffer instead of possibly using a static data area that may be overwritten by an unrelated call from another thread.

Я всё искала её в VC++, но не нашла, даже в книжке Джефри Рихтера пыталась найти что-то что было про это ^^ А потом вспомнила, что вообще-то для проекта можно выбирать версию библиотеки C, в том числе и многопоточную, так что стало ясно, что там всё предусмотрено ^^

http://www.opengroup.org/onlinepubs/000095399/functions/strtok.html

Вот код на VB:

Option Explicit

'====================================================================
Public Sub Main()
 MsgBox CreateComplexDirectory("App\Test\Win32\..\Data\")
 MsgBox CreateComplexDirectory("App/Test/Win16/Data")
End Sub

' Принимаются и прямые слэши.
Private Function CreateComplexDirectory(ByVal Path As BStr) As Boolean
 Dim Elements() As BStr
 Dim TMP As Long
 Dim RC As Long
 Dim NewPath As BStr
 
 Path = Replace(Path, "/", "\")
 Path = asGetFullFileName(Path)
 If Right(Path, 1) = "\" Then Path = asRemoveBackslash(Path)
 If Path = "" Then Exit Function
 
 Elements = Split(Path, "\")
 For TMP = LBound(Elements) To UBound(Elements)
   If NewPath = "" Then
     NewPath = Elements(TMP)
   Else
     NewPath = asBuildFileName(NewPath, Elements(TMP))
   End If
   
   If Not asIsDirectoryExist(NewPath) Then
     RC = CreateDirectory(NewPath, 0)
     If RC = 0 Then Exit Function
   End If
 Next TMP
 
 CreateComplexDirectory = True
End Function



Функция получает каталог и создаёт его. Тоесть он может состоять из нескольких подкаталогов, и все они будут созданы. Я где-то в какой-то библиотеке вроде ShlWAPI.DLL видела такое, но не нашла. Пришлось писать самой.

А вот как это на C++:

#include <AJP System.H>
#include <AJP Console.H>
#include <xShlWAPI.H>
#include <string.h>

//===================================================================
BOOL __IsDirectory(char *FileName)
{
 DWORD Attribs = GetFileAttributes(FileName)&#59;
 if (Attribs == 0xFFFFFFFF)
   return FALSE&#59;
 else {
   if (Attribs & FILE_ATTRIBUTE_DIRECTORY)
     return TRUE&#59;
   else
     return FALSE&#59;
 }
}

BOOL __IsFileOrDirectoryExist(char *FileName)
{
 // GetLongPathName() и GetShortPathName() работают и с масками,
 // возвращая первый соответствующий файл. Поэтому использовать эти
 // функции нельзя, ведь мы ищем реальный файл. Зато
 // GetFileAttributes() возвращает ошибку, если файла нет.
 DWORD Attribs = GetFileAttributes(FileName)&#59;
 if (Attribs == 0xFFFFFFFF)
   return FALSE&#59;
 else
   return TRUE&#59;
}

BOOL __IsDirectoryExist(char *FileName)
{
 if (__IsFileOrDirectoryExist(FileName))
   return __IsDirectory(FileName)&#59;
 else
   return FALSE&#59;
}

//===================================================================
BOOL CreateComplexDirectory(char *szPath)
{
 CUniversalString ucPath(szPath)&#59;
 CUniversalString ucFullPath(10)&#59;
 CUniversalString ucNewPath(10)&#59;
 int TMP = 0&#59;
 
 // Заменяем все прямые слэши обратными...
 for (TMP = 0&#59; TMP < lstrlen(ucPath)&#59; TMP++) {
   if (ucPath.ValueA[TMP] == '/') ucPath.ValueA[TMP] = '\\'&#59;
 }
 
 // Теперь преобразуем в абсолютный путь...
 DWORD RC = GetFullPathName(ucPath, 0, ucFullPath, (LPSTR*)&TMP)&#59;
 if (RC == 0) return FALSE&#59;
 
 ucFullPath.Alloc(RC + 1)&#59;
 RC = GetFullPathName(ucPath, RC, ucFullPath, (LPSTR*)&TMP)&#59;
 if (RC == 0 || RC > ucFullPath.SizeA()) return FALSE&#59;
 
 // И удаляем последний бэкслэш...
 PathRemoveBackslash(ucFullPath)&#59;
 
 // Теперь режем и на составляющие...
 ucNewPath.Alloc(ucFullPath.SizeA() + 10)&#59;
 
 char *Token = strtok(ucFullPath, "\\")&#59;
 if (Token == NULL) return FALSE&#59;
 
 for ( &#59; Token != NULL&#59; ) {
   if (lstrlen(ucNewPath) == 0)
     lstrcpy(ucNewPath, Token)&#59;
   else {
     PathAddBackslash(ucNewPath)&#59;
     lstrcat(ucNewPath, Token)&#59;
   }
   
   if (!__IsDirectoryExist(ucNewPath)) {
     RC = CreateDirectory(ucNewPath, NULL)&#59;
     if (RC == 0) return FALSE&#59;
   }
   
   Token = strtok(NULL, "\\")&#59;
 }
 
 return TRUE&#59;
}

//===================================================================
int main()
{
 SetCurrentDirectory("C:\\Мои документы\\VCPP\\TempProject\\")&#59;
 
 cout << CreateComplexDirectory("App\\Test\\Win32\\..\\Data\\") << endl&#59;
 cout << CreateComplexDirectory("App/Test/Win16/Data") << endl&#59;
 
 return 0&#59;
}



CUniversalString - это класс-контейнер для строки. Конструктор с char* создаёт внутренний буфер и копирует в него строку. Конструктор с цифрой создаёт буфер заданной длины. Alloc - пересоздаёт буфер, SizeA - возвращает его размер, ValueA - сам буфер, а ещё класс кастуется к LPSTR.

На самом деле там два буфера, и класс создан для перекодировки ANSI-UNICODE, но это не одна его задача. Кроме того, класс буду переписывать - два буфера одновременно - это расточительно...

Кстати, заметьте разницу в размере кода. Да, кое-что уже реализовано в виде отдельных функций, но на VB всё равно кода много не прибавилось. За это я и люблю VB.