git

Форк
0
/
winansi.c 
683 строки · 16.5 Кб
1
/*
2
 * Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
3
 */
4

5
#undef NOGDI
6

7
#include "../git-compat-util.h"
8
#include <wingdi.h>
9
#include <winreg.h>
10
#include "win32.h"
11
#include "win32/lazyload.h"
12

13
static int fd_is_interactive[3] = { 0, 0, 0 };
14
#define FD_CONSOLE 0x1
15
#define FD_SWAPPED 0x2
16
#define FD_MSYS    0x4
17

18
/*
19
 ANSI codes used by git: m, K
20

21
 This file is git-specific. Therefore, this file does not attempt
22
 to implement any codes that are not used by git.
23
*/
24

25
static HANDLE console;
26
static WORD plain_attr;
27
static WORD attr;
28
static int negative;
29
static int non_ascii_used = 0;
30
static HANDLE hthread, hread, hwrite;
31
static HANDLE hconsole1, hconsole2;
32

33
#ifdef __MINGW32__
34
#if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 5
35
typedef struct _CONSOLE_FONT_INFOEX {
36
	ULONG cbSize;
37
	DWORD nFont;
38
	COORD dwFontSize;
39
	UINT FontFamily;
40
	UINT FontWeight;
41
	WCHAR FaceName[LF_FACESIZE];
42
} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
43
#endif
44
#endif
45

46
static void warn_if_raster_font(void)
47
{
48
	DWORD fontFamily = 0;
49
	DECLARE_PROC_ADDR(kernel32.dll, BOOL, WINAPI,
50
			GetCurrentConsoleFontEx, HANDLE, BOOL,
51
			PCONSOLE_FONT_INFOEX);
52

53
	/* don't bother if output was ascii only */
54
	if (!non_ascii_used)
55
		return;
56

57
	/* GetCurrentConsoleFontEx is available since Vista */
58
	if (INIT_PROC_ADDR(GetCurrentConsoleFontEx)) {
59
		CONSOLE_FONT_INFOEX cfi;
60
		cfi.cbSize = sizeof(cfi);
61
		if (GetCurrentConsoleFontEx(console, 0, &cfi))
62
			fontFamily = cfi.FontFamily;
63
	} else {
64
		/* pre-Vista: check default console font in registry */
65
		HKEY hkey;
66
		if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console",
67
				0, KEY_READ, &hkey)) {
68
			DWORD size = sizeof(fontFamily);
69
			RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
70
					(LPVOID) &fontFamily, &size);
71
			RegCloseKey(hkey);
72
		}
73
	}
74

75
	if (!(fontFamily & TMPF_TRUETYPE)) {
76
		const wchar_t *msg = L"\nWarning: Your console font probably "
77
			L"doesn\'t support Unicode. If you experience strange "
78
			L"characters in the output, consider switching to a "
79
			L"TrueType font such as Consolas!\n";
80
		DWORD dummy;
81
		WriteConsoleW(console, msg, wcslen(msg), &dummy, NULL);
82
	}
83
}
84

85
static int is_console(int fd)
86
{
87
	CONSOLE_SCREEN_BUFFER_INFO sbi;
88
	DWORD mode;
89
	HANDLE hcon;
90

91
	static int initialized = 0;
92

93
	/* get OS handle of the file descriptor */
94
	hcon = (HANDLE) _get_osfhandle(fd);
95
	if (hcon == INVALID_HANDLE_VALUE)
96
		return 0;
97

98
	/* check if its a device (i.e. console, printer, serial port) */
99
	if (GetFileType(hcon) != FILE_TYPE_CHAR)
100
		return 0;
101

102
	/* check if its a handle to a console output screen buffer */
103
	if (!fd) {
104
		if (!GetConsoleMode(hcon, &mode))
105
			return 0;
106
		/*
107
		 * This code path is only reached if there is no console
108
		 * attached to stdout/stderr, i.e. we will not need to output
109
		 * any text to any console, therefore we might just as well
110
		 * use black as foreground color.
111
		 */
112
		sbi.wAttributes = 0;
113
	} else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
114
		return 0;
115

116
	if (fd >= 0 && fd <= 2)
117
		fd_is_interactive[fd] |= FD_CONSOLE;
118

119
	/* initialize attributes */
120
	if (!initialized) {
121
		console = hcon;
122
		attr = plain_attr = sbi.wAttributes;
123
		negative = 0;
124
		initialized = 1;
125
	}
126

127
	return 1;
128
}
129

130
#define BUFFER_SIZE 4096
131
#define MAX_PARAMS 16
132

133
static void write_console(unsigned char *str, size_t len)
134
{
135
	/* only called from console_thread, so a static buffer will do */
136
	static wchar_t wbuf[2 * BUFFER_SIZE + 1];
137
	DWORD dummy;
138

139
	/* convert utf-8 to utf-16 */
140
	int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
141
	if (wlen < 0) {
142
		const wchar_t *err = L"[invalid]";
143
		WriteConsoleW(console, err, wcslen(err), &dummy, NULL);
144
		return;
145
	}
146

147
	/* write directly to console */
148
	WriteConsoleW(console, wbuf, wlen, &dummy, NULL);
149

150
	/* remember if non-ascii characters are printed */
151
	if (wlen != len)
152
		non_ascii_used = 1;
153
}
154

155
#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
156
#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
157

158
static void set_console_attr(void)
159
{
160
	WORD attributes = attr;
161
	if (negative) {
162
		attributes &= ~FOREGROUND_ALL;
163
		attributes &= ~BACKGROUND_ALL;
164

165
		/* This could probably use a bitmask
166
		   instead of a series of ifs */
167
		if (attr & FOREGROUND_RED)
168
			attributes |= BACKGROUND_RED;
169
		if (attr & FOREGROUND_GREEN)
170
			attributes |= BACKGROUND_GREEN;
171
		if (attr & FOREGROUND_BLUE)
172
			attributes |= BACKGROUND_BLUE;
173

174
		if (attr & BACKGROUND_RED)
175
			attributes |= FOREGROUND_RED;
176
		if (attr & BACKGROUND_GREEN)
177
			attributes |= FOREGROUND_GREEN;
178
		if (attr & BACKGROUND_BLUE)
179
			attributes |= FOREGROUND_BLUE;
180
	}
181
	SetConsoleTextAttribute(console, attributes);
182
}
183

184
static void erase_in_line(void)
185
{
186
	CONSOLE_SCREEN_BUFFER_INFO sbi;
187
	DWORD dummy; /* Needed for Windows 7 (or Vista) regression */
188

189
	if (!console)
190
		return;
191

192
	GetConsoleScreenBufferInfo(console, &sbi);
193
	FillConsoleOutputCharacterA(console, ' ',
194
		sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
195
		&dummy);
196
}
197

198
static void set_attr(char func, const int *params, int paramlen)
199
{
200
	int i;
201
	switch (func) {
202
	case 'm':
203
		for (i = 0; i < paramlen; i++) {
204
			switch (params[i]) {
205
			case 0: /* reset */
206
				attr = plain_attr;
207
				negative = 0;
208
				break;
209
			case 1: /* bold */
210
				attr |= FOREGROUND_INTENSITY;
211
				break;
212
			case 2:  /* faint */
213
			case 22: /* normal */
214
				attr &= ~FOREGROUND_INTENSITY;
215
				break;
216
			case 3:  /* italic */
217
				/* Unsupported */
218
				break;
219
			case 4:  /* underline */
220
			case 21: /* double underline */
221
				/* Wikipedia says this flag does nothing */
222
				/* Furthermore, mingw doesn't define this flag
223
				attr |= COMMON_LVB_UNDERSCORE; */
224
				break;
225
			case 24: /* no underline */
226
				/* attr &= ~COMMON_LVB_UNDERSCORE; */
227
				break;
228
			case 5:  /* slow blink */
229
			case 6:  /* fast blink */
230
				/* We don't have blink, but we do have
231
				   background intensity */
232
				attr |= BACKGROUND_INTENSITY;
233
				break;
234
			case 25: /* no blink */
235
				attr &= ~BACKGROUND_INTENSITY;
236
				break;
237
			case 7:  /* negative */
238
				negative = 1;
239
				break;
240
			case 27: /* positive */
241
				negative = 0;
242
				break;
243
			case 8:  /* conceal */
244
			case 28: /* reveal */
245
				/* Unsupported */
246
				break;
247
			case 30: /* Black */
248
				attr &= ~FOREGROUND_ALL;
249
				break;
250
			case 31: /* Red */
251
				attr &= ~FOREGROUND_ALL;
252
				attr |= FOREGROUND_RED;
253
				break;
254
			case 32: /* Green */
255
				attr &= ~FOREGROUND_ALL;
256
				attr |= FOREGROUND_GREEN;
257
				break;
258
			case 33: /* Yellow */
259
				attr &= ~FOREGROUND_ALL;
260
				attr |= FOREGROUND_RED | FOREGROUND_GREEN;
261
				break;
262
			case 34: /* Blue */
263
				attr &= ~FOREGROUND_ALL;
264
				attr |= FOREGROUND_BLUE;
265
				break;
266
			case 35: /* Magenta */
267
				attr &= ~FOREGROUND_ALL;
268
				attr |= FOREGROUND_RED | FOREGROUND_BLUE;
269
				break;
270
			case 36: /* Cyan */
271
				attr &= ~FOREGROUND_ALL;
272
				attr |= FOREGROUND_GREEN | FOREGROUND_BLUE;
273
				break;
274
			case 37: /* White */
275
				attr |= FOREGROUND_RED |
276
					FOREGROUND_GREEN |
277
					FOREGROUND_BLUE;
278
				break;
279
			case 38: /* Unknown */
280
				break;
281
			case 39: /* reset */
282
				attr &= ~FOREGROUND_ALL;
283
				attr |= (plain_attr & FOREGROUND_ALL);
284
				break;
285
			case 40: /* Black */
286
				attr &= ~BACKGROUND_ALL;
287
				break;
288
			case 41: /* Red */
289
				attr &= ~BACKGROUND_ALL;
290
				attr |= BACKGROUND_RED;
291
				break;
292
			case 42: /* Green */
293
				attr &= ~BACKGROUND_ALL;
294
				attr |= BACKGROUND_GREEN;
295
				break;
296
			case 43: /* Yellow */
297
				attr &= ~BACKGROUND_ALL;
298
				attr |= BACKGROUND_RED | BACKGROUND_GREEN;
299
				break;
300
			case 44: /* Blue */
301
				attr &= ~BACKGROUND_ALL;
302
				attr |= BACKGROUND_BLUE;
303
				break;
304
			case 45: /* Magenta */
305
				attr &= ~BACKGROUND_ALL;
306
				attr |= BACKGROUND_RED | BACKGROUND_BLUE;
307
				break;
308
			case 46: /* Cyan */
309
				attr &= ~BACKGROUND_ALL;
310
				attr |= BACKGROUND_GREEN | BACKGROUND_BLUE;
311
				break;
312
			case 47: /* White */
313
				attr |= BACKGROUND_RED |
314
					BACKGROUND_GREEN |
315
					BACKGROUND_BLUE;
316
				break;
317
			case 48: /* Unknown */
318
				break;
319
			case 49: /* reset */
320
				attr &= ~BACKGROUND_ALL;
321
				attr |= (plain_attr & BACKGROUND_ALL);
322
				break;
323
			default:
324
				/* Unsupported code */
325
				break;
326
			}
327
		}
328
		set_console_attr();
329
		break;
330
	case 'K':
331
		erase_in_line();
332
		break;
333
	default:
334
		/* Unsupported code */
335
		break;
336
	}
337
}
338

339
enum {
340
	TEXT = 0, ESCAPE = 033, BRACKET = '['
341
};
342

343
static DWORD WINAPI console_thread(LPVOID unused)
344
{
345
	unsigned char buffer[BUFFER_SIZE];
346
	DWORD bytes;
347
	int start, end = 0, c, parampos = 0, state = TEXT;
348
	int params[MAX_PARAMS];
349

350
	while (1) {
351
		/* read next chunk of bytes from the pipe */
352
		if (!ReadFile(hread, buffer + end, BUFFER_SIZE - end, &bytes,
353
				NULL)) {
354
			/* exit if pipe has been closed or disconnected */
355
			if (GetLastError() == ERROR_PIPE_NOT_CONNECTED ||
356
					GetLastError() == ERROR_BROKEN_PIPE)
357
				break;
358
			/* ignore other errors */
359
			continue;
360
		}
361

362
		/* scan the bytes and handle ANSI control codes */
363
		bytes += end;
364
		start = end = 0;
365
		while (end < bytes) {
366
			c = buffer[end++];
367
			switch (state) {
368
			case TEXT:
369
				if (c == ESCAPE) {
370
					/* print text seen so far */
371
					if (end - 1 > start)
372
						write_console(buffer + start,
373
							end - 1 - start);
374

375
					/* then start parsing escape sequence */
376
					start = end - 1;
377
					memset(params, 0, sizeof(params));
378
					parampos = 0;
379
					state = ESCAPE;
380
				}
381
				break;
382

383
			case ESCAPE:
384
				/* continue if "\033[", otherwise bail out */
385
				state = (c == BRACKET) ? BRACKET : TEXT;
386
				break;
387

388
			case BRACKET:
389
				/* parse [0-9;]* into array of parameters */
390
				if (c >= '0' && c <= '9') {
391
					params[parampos] *= 10;
392
					params[parampos] += c - '0';
393
				} else if (c == ';') {
394
					/*
395
					 * next parameter, bail out if out of
396
					 * bounds
397
					 */
398
					parampos++;
399
					if (parampos >= MAX_PARAMS)
400
						state = TEXT;
401
				} else {
402
					/*
403
					 * end of escape sequence, change
404
					 * console attributes
405
					 */
406
					set_attr(c, params, parampos + 1);
407
					start = end;
408
					state = TEXT;
409
				}
410
				break;
411
			}
412
		}
413

414
		/* print remaining text unless parsing an escape sequence */
415
		if (state == TEXT && end > start) {
416
			/* check for incomplete UTF-8 sequences and fix end */
417
			if (buffer[end - 1] >= 0x80) {
418
				if (buffer[end -1] >= 0xc0)
419
					end--;
420
				else if (end - 1 > start &&
421
						buffer[end - 2] >= 0xe0)
422
					end -= 2;
423
				else if (end - 2 > start &&
424
						buffer[end - 3] >= 0xf0)
425
					end -= 3;
426
			}
427

428
			/* print remaining complete UTF-8 sequences */
429
			if (end > start)
430
				write_console(buffer + start, end - start);
431

432
			/* move remaining bytes to the front */
433
			if (end < bytes)
434
				memmove(buffer, buffer + end, bytes - end);
435
			end = bytes - end;
436
		} else {
437
			/* all data has been consumed, mark buffer empty */
438
			end = 0;
439
		}
440
	}
441

442
	/* check if the console font supports unicode */
443
	warn_if_raster_font();
444

445
	CloseHandle(hread);
446
	return 0;
447
}
448

449
static void winansi_exit(void)
450
{
451
	/* flush all streams */
452
	_flushall();
453

454
	/* signal console thread to exit */
455
	FlushFileBuffers(hwrite);
456
	DisconnectNamedPipe(hwrite);
457

458
	/* wait for console thread to copy remaining data */
459
	WaitForSingleObject(hthread, INFINITE);
460

461
	/* cleanup handles... */
462
	CloseHandle(hwrite);
463
	CloseHandle(hthread);
464
}
465

466
static void die_lasterr(const char *fmt, ...)
467
{
468
	va_list params;
469
	va_start(params, fmt);
470
	errno = err_win_to_posix(GetLastError());
471
	die_errno(fmt, params);
472
	va_end(params);
473
}
474

475
#undef dup2
476
int winansi_dup2(int oldfd, int newfd)
477
{
478
	int ret = dup2(oldfd, newfd);
479

480
	if (!ret && newfd >= 0 && newfd <= 2)
481
		fd_is_interactive[newfd] = oldfd < 0 || oldfd > 2 ?
482
			0 : fd_is_interactive[oldfd];
483

484
	return ret;
485
}
486

487
static HANDLE duplicate_handle(HANDLE hnd)
488
{
489
	HANDLE hresult, hproc = GetCurrentProcess();
490
	if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE,
491
			DUPLICATE_SAME_ACCESS))
492
		die_lasterr("DuplicateHandle(%li) failed",
493
			(long) (intptr_t) hnd);
494
	return hresult;
495
}
496

497
static HANDLE swap_osfhnd(int fd, HANDLE new_handle)
498
{
499
	/*
500
	 * Create a copy of the original handle associated with fd
501
	 * because the original will get closed when we dup2().
502
	 */
503
	HANDLE handle = (HANDLE)_get_osfhandle(fd);
504
	HANDLE duplicate = duplicate_handle(handle);
505

506
	/* Create a temp fd associated with the already open "new_handle". */
507
	int new_fd = _open_osfhandle((intptr_t)new_handle, O_BINARY);
508

509
	assert((fd == 1) || (fd == 2));
510

511
	/*
512
	 * Use stock dup2() to re-bind fd to the new handle.  Note that
513
	 * this will implicitly close(1) and close both fd=1 and the
514
	 * originally associated handle.  It will open a new fd=1 and
515
	 * call DuplicateHandle() on the handle associated with new_fd.
516
	 * It is because of this implicit close() that we created the
517
	 * copy of the original.
518
	 *
519
	 * Note that we need to update the cached console handle to the
520
	 * duplicated one because the dup2() call will implicitly close
521
	 * the original one.
522
	 *
523
	 * Note that dup2() when given target := {0,1,2} will also
524
	 * call SetStdHandle(), so we don't need to worry about that.
525
	 */
526
	if (console == handle)
527
		console = duplicate;
528
	dup2(new_fd, fd);
529

530
	/* Close the temp fd.  This explicitly closes "new_handle"
531
	 * (because it has been associated with it).
532
	 */
533
	close(new_fd);
534

535
	if (fd == 2)
536
		setvbuf(stderr, NULL, _IONBF, BUFSIZ);
537
	fd_is_interactive[fd] |= FD_SWAPPED;
538

539
	return duplicate;
540
}
541

542
#ifdef DETECT_MSYS_TTY
543

544
#include <winternl.h>
545

546
#if defined(_MSC_VER)
547

548
typedef struct _OBJECT_NAME_INFORMATION
549
{
550
	UNICODE_STRING Name;
551
	WCHAR NameBuffer[FLEX_ARRAY];
552
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
553

554
#define ObjectNameInformation 1
555

556
#else
557
#include <ntstatus.h>
558
#endif
559

560
static void detect_msys_tty(int fd)
561
{
562
	ULONG result;
563
	BYTE buffer[1024];
564
	POBJECT_NAME_INFORMATION nameinfo = (POBJECT_NAME_INFORMATION) buffer;
565
	PWSTR name;
566

567
	/* check if fd is a pipe */
568
	HANDLE h = (HANDLE) _get_osfhandle(fd);
569
	if (GetFileType(h) != FILE_TYPE_PIPE)
570
		return;
571

572
	/* get pipe name */
573
	if (!NT_SUCCESS(NtQueryObject(h, ObjectNameInformation,
574
			buffer, sizeof(buffer) - 2, &result)))
575
		return;
576
	name = nameinfo->Name.Buffer;
577
	name[nameinfo->Name.Length / sizeof(*name)] = 0;
578

579
	/*
580
	 * Check if this could be a MSYS2 pty pipe ('msys-XXXX-ptyN-XX')
581
	 * or a cygwin pty pipe ('cygwin-XXXX-ptyN-XX')
582
	 */
583
	if ((!wcsstr(name, L"msys-") && !wcsstr(name, L"cygwin-")) ||
584
			!wcsstr(name, L"-pty"))
585
		return;
586

587
	if (fd == 2)
588
		setvbuf(stderr, NULL, _IONBF, BUFSIZ);
589
	fd_is_interactive[fd] |= FD_MSYS;
590
}
591

592
#endif
593

594
/*
595
 * Wrapper for isatty().  Most calls in the main git code
596
 * call isatty(1 or 2) to see if the instance is interactive
597
 * and should: be colored, show progress, paginate output.
598
 * We lie and give results for what the descriptor WAS at
599
 * startup (and ignore any pipe redirection we internally
600
 * do).
601
 */
602
#undef isatty
603
int winansi_isatty(int fd)
604
{
605
	if (fd >= 0 && fd <= 2)
606
		return fd_is_interactive[fd] != 0;
607
	return isatty(fd);
608
}
609

610
void winansi_init(void)
611
{
612
	int con1, con2;
613
	wchar_t name[32];
614

615
	/* check if either stdout or stderr is a console output screen buffer */
616
	con1 = is_console(1);
617
	con2 = is_console(2);
618

619
	/* Also compute console bit for fd 0 even though we don't need the result here. */
620
	is_console(0);
621

622
	if (!con1 && !con2) {
623
#ifdef DETECT_MSYS_TTY
624
		/* check if stdin / stdout / stderr are MSYS2 pty pipes */
625
		detect_msys_tty(0);
626
		detect_msys_tty(1);
627
		detect_msys_tty(2);
628
#endif
629
		return;
630
	}
631

632
	/* create a named pipe to communicate with the console thread */
633
	if (swprintf(name, ARRAY_SIZE(name) - 1, L"\\\\.\\pipe\\winansi%lu",
634
		     GetCurrentProcessId()) < 0)
635
		die("Could not initialize winansi pipe name");
636
	hwrite = CreateNamedPipeW(name, PIPE_ACCESS_OUTBOUND,
637
		PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL);
638
	if (hwrite == INVALID_HANDLE_VALUE)
639
		die_lasterr("CreateNamedPipe failed");
640

641
	hread = CreateFileW(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
642
	if (hread == INVALID_HANDLE_VALUE)
643
		die_lasterr("CreateFile for named pipe failed");
644

645
	/* start console spool thread on the pipe's read end */
646
	hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL);
647
	if (!hthread)
648
		die_lasterr("CreateThread(console_thread) failed");
649

650
	/* schedule cleanup routine */
651
	if (atexit(winansi_exit))
652
		die_errno("atexit(winansi_exit) failed");
653

654
	/* redirect stdout / stderr to the pipe */
655
	if (con1)
656
		hconsole1 = swap_osfhnd(1, duplicate_handle(hwrite));
657
	if (con2)
658
		hconsole2 = swap_osfhnd(2, duplicate_handle(hwrite));
659
}
660

661
/*
662
 * Returns the real console handle if stdout / stderr is a pipe redirecting
663
 * to the console. Allows spawn / exec to pass the console to the next process.
664
 */
665
HANDLE winansi_get_osfhandle(int fd)
666
{
667
	HANDLE ret;
668

669
	if (fd == 1 && (fd_is_interactive[1] & FD_SWAPPED))
670
		return hconsole1;
671
	if (fd == 2 && (fd_is_interactive[2] & FD_SWAPPED))
672
		return hconsole2;
673

674
	ret = (HANDLE)_get_osfhandle(fd);
675

676
	/*
677
	 * There are obviously circumstances under which _get_osfhandle()
678
	 * returns (HANDLE)-2. This is not documented anywhere, but that is so
679
	 * clearly an invalid handle value that we can just work around this
680
	 * and return the correct value for invalid handles.
681
	 */
682
	return ret == (HANDLE)-2 ? INVALID_HANDLE_VALUE : ret;
683
}
684

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.