LINUX.ORG.RU

Сообщения u5er

 

Проверка большого числа условий на си

Форум — Development

Сейчас я пишу такой код:

	if( phonebookEntry->index < 0 && phonebookEntry->telNo && !phonebookEntry->name ){
		//только телефон
	}else if( phonebookEntry->index < 0 && phonebookEntry->telNo && phonebookEntry->name ){
		//телефон и имя
	}else if( phonebookEntry->index >= 0 && !phonebookEntry->telNo && !phonebookEntry->name ){
		//только индекс
	}else if( phonebookEntry->index >= 0 && phonebookEntry->telNo && !phonebookEntry->name ){
		//индекс и телефон
	}else if( phonebookEntry->index >= 0 && phonebookEntry->telNo && phonebookEntry->name ){
		//индекс, телефон и имя
	}else{
		//недопустимое сочетание
	}

И я заметил, что в каждом условном операторе сразу проверяется случая и подумал, а что если поступить вот так:

	unsigned int condition = 0;
	
	if( phonebookEntry->index >= 0 ) condition |= 1;
	if( phonebookEntry->telNo      ) condition |= 1 << 1;
	if( phonebookEntry->name       ) condition |= 1 << 2;

И дальше переменную condition запихнуть в switch или вообще использовать в качестве индекса в массиве указателей? Мой случай ещё пограничный, но если добавить ещё один параметр, то вариантов уже будет 16! Короче, степень двойки. Я один такой упоротый или такое где-нибудь применяется?

 

u5er
()

Функции с переменным числом аргументов: va_arg vs void*

Форум — Development

Пытаюсь выбрать наиболее подходящий вариант. Речь идёт о тех случаях, когда количество и тип переменных заранее известно, но вызов должен происходить через некий интерфейс, как, например, через syscall. Фактически, я сейчас пытаюсь определиться между двумя вариантами:

int api1( unsigned int id, ... );
int api2( unsigned int id, const void* arg );

В случае api1 предполагается передавать набор аргументов в зависимости от id.

В случае api2 предполагается передавать указатель на некую структуру, которая будет отличаться в зависимости от id и в которой будет виден весь список аргументов.

Пока что склоняюсь ко второму способу, потому что, во-первых, структуру можно будет объявить заранее статически, а во-вторых, виден список аргументов. Цена вопроса - размер указателя.

А какой вариант предпочли бы вы? Или может существуют ещё способы?

 

u5er
()

Рисовалка битмапов на тикле

Форум — Development

Я тут под свои нужды накидал простенький редактор битмапок, который позволит кабанчиком рисовать небольшие пиктограммки. Получилось довольно неплохо и я решил поделиться им с сообществом. Код простой, поэтому легко будет подстроить под свои нужны.

Перемещение фукуса стрелочками. Для рисования/стирания пикселя используется пробел. По нажатию кнопки «Dump» в консоль выплёвывается последовательность 0 и 1 в виде текста, которую дальше можете сконвертировать в тот формат, который вам нужен.

Пример использования https://0x0.st/Kf8v.png

#!/usr/bin/wish

##########################
###   settings start   ###


set bitmapWidth  32
set bitmapHeight 32


###    settings end    ###
##########################

set currentFocusX 0
set currentFocusY 0

set verticalSymmetry   0
set horizontalSymmetry 0
set diagonalSymmetry   0


ttk::style layout pixel.TCheckbutton {
	Checkbutton.indicator
	Checkbutton.focus
}


proc focusUp { } {
	
	if { $::currentFocusY > 0 } {
		incr ::currentFocusY -1
	}
	
	focus .checkboxArea.pixelr${::currentFocusY}c${::currentFocusX}
}

proc focusDown { } {
	
	if { $::currentFocusY < [expr $::bitmapHeight - 1] } {
		incr ::currentFocusY
	}
	
	focus .checkboxArea.pixelr${::currentFocusY}c${::currentFocusX}
}

proc focusLeft { } {
	
	if { $::currentFocusX > 0 } {
		incr ::currentFocusX -1
	}
	
	focus .checkboxArea.pixelr${::currentFocusY}c${::currentFocusX}
}

proc focusRight { } {
	
	if { $::currentFocusX < [expr $::bitmapWidth - 1] } {
		incr ::currentFocusX
	}
	
	focus .checkboxArea.pixelr${::currentFocusY}c${::currentFocusX}
}

proc shiftUp { } {
	
	for { set rowNo 1 } { $rowNo < $::bitmapHeight } { incr rowNo } {
		
		set rowNoTo [expr $rowNo - 1]
		
		for { set colNo 0 } { $colNo < $::bitmapWidth } { incr colNo } {
			set ::pixelr${rowNoTo}c${colNo} [ set ::pixelr${rowNo}c${colNo} ]
		}
	}
}

proc shiftLeft { } {
	
	for { set colNo 1 } { $colNo < $::bitmapWidth } { incr colNo } {
		
		set colNoTo [ expr $colNo - 1 ]
		
		for { set rowNo 0 } { $rowNo < $::bitmapHeight } { incr rowNo } {
			set ::pixelr${rowNo}c${colNoTo} [ set ::pixelr${rowNo}c${colNo} ]
		}
	}
}
proc shiftRight { } {
	
	if { $::bitmapWidth < 2 } return
	
	for { set colNo [expr $::bitmapWidth - 2] } { $colNo >= 0 } { incr colNo -1 } {
		
		set colNoTo [ expr $colNo + 1 ]
		
		for { set rowNo 0 } { $rowNo < $::bitmapHeight } { incr rowNo } {
			set ::pixelr${rowNo}c${colNoTo} [ set ::pixelr${rowNo}c${colNo} ]
		}
	}
}

proc shiftDown { } {
	
	if { $::bitmapHeight < 2 } return
	
	for { set rowNo [expr $::bitmapHeight - 2] } { $rowNo >= 0 } { incr rowNo -1 } {
		
		set rowNoTo [ expr $rowNo + 1 ]
		
		for { set colNo 0 } { $colNo < $::bitmapWidth } { incr colNo } {
			set ::pixelr${rowNoTo}c${colNo} [ set ::pixelr${rowNo}c${colNo}]
		}
	}
}



proc setAllPixelsValue { value } {
	for { set rowNo 0 } { $rowNo < $::bitmapHeight } { incr rowNo } {
		for { set colNo 0 } { $colNo < $::bitmapWidth } { incr colNo } {
			set ::pixelr${rowNo}c${colNo} $value
		}
	}
}

proc verticalSymmetryHandler { rowNo colNo } {
	set mirrorCol [ expr $::bitmapWidth - $colNo - 1 ]
	set ::pixelr${rowNo}c${mirrorCol} [ set ::pixelr${rowNo}c${colNo} ]
}

proc horizontalSymmetryHandler { rowNo colNo } {
	set mirrorRow [ expr $::bitmapHeight - $rowNo - 1 ]
	set ::pixelr${mirrorRow}c${colNo} [ set ::pixelr${rowNo}c${colNo} ]
}

proc diagonalSymmetryHandler { rowNo colNo } {
	
	set diagonalRow [ expr $::bitmapWidth - $rowNo - 1 ]
	set diagonalCol [ expr $::bitmapWidth - $colNo - 1 ]
	
	set ::pixelr${diagonalRow}c${diagonalCol} [ set ::pixelr${rowNo}c${colNo} ]
}
 
proc symmetryHandler { rowNo colNo } {
	
	if { $::verticalSymmetry } {
		verticalSymmetryHandler $rowNo $colNo
	}
	
	if { $::horizontalSymmetry } {
		horizontalSymmetryHandler $rowNo $colNo
	}
	
	if { $::diagonalSymmetry } {
		diagonalSymmetryHandler $rowNo $colNo
	}
}

proc dumpPixelmap { } {
	
	puts ""
	
	for { set rowNo 0 } { $rowNo < $::bitmapHeight } { incr rowNo } {
		for { set colNo 0 } { $colNo < $::bitmapWidth } { incr colNo } {
			puts -nonewline [set ::pixelr${rowNo}c${colNo}]
		}
	}
	
	puts ""
	puts ""
}

proc buildCheckboxArea { } {
	
	for { set rowNo 0 } { $rowNo < 32 } { incr rowNo } {
		
		for { set colNo 0 } { $colNo < 32 } { incr colNo } {
			
			ttk::checkbutton .checkboxArea.pixelr${rowNo}c${colNo} -style pixel.TCheckbutton -variable pixelr${rowNo}c${colNo} -command "symmetryHandler $rowNo $colNo"
			grid .checkboxArea.pixelr${rowNo}c${colNo} -row $rowNo -column $colNo
			
			set ::pixelr${rowNo}c${colNo}  0
			
		}
	}
}


proc buildGui { } {
	
	set buttonsPaddingY 30
	
	# window layout
	ttk::frame .checkboxArea
	ttk::frame .controlPanel
	grid .checkboxArea  -row 0 -column 0 -padx 10 -pady 10
	grid .controlPanel  -row 0 -column 1 -padx 10 -pady 10
	
	#chechbox area build
	buildCheckboxArea
	
	#control panel
	
	#sel clear
	ttk::button .controlPanel.allClear -text "All clear" -command { setAllPixelsValue 0 }
	ttk::button .controlPanel.allSet   -text "All set"   -command { setAllPixelsValue 1 }
	
	grid .controlPanel.allClear -row 0 -column 0
	grid .controlPanel.allSet   -row 10 -column 0
	
	
	#shift panel
	ttk::frame .controlPanel.shift
	grid .controlPanel.shift  -row 20 -column 0 -pady $buttonsPaddingY
	
	
	ttk::button .controlPanel.shift.up    -text "/\\" -command shiftUp 
	ttk::button .controlPanel.shift.left  -text "<"   -command shiftLeft
	ttk::button .controlPanel.shift.right -text ">"   -command shiftRight
	ttk::button .controlPanel.shift.down  -text "\\/" -command shiftDown
	
	grid .controlPanel.shift.up    -row 0 -column 1
	grid .controlPanel.shift.left  -row 1 -column 0
	grid .controlPanel.shift.right -row 1 -column 2
	grid .controlPanel.shift.down  -row 2 -column 1
	
	
	#symmetry settings
	ttk::frame .controlPanel.symmetry
	grid       .controlPanel.symmetry -row 30 -column 0 -pady $buttonsPaddingY
	
	ttk::checkbutton .controlPanel.symmetry.vertical   -text "Вертикальная симметрия"   -variable verticalSymmetry
	ttk::checkbutton .controlPanel.symmetry.horizontal -text "Горизонтальная симметрия" -variable horizontalSymmetry
	ttk::checkbutton .controlPanel.symmetry.diagonal   -text "Диагональная симметрия" -variable diagonalSymmetry
	
	grid .controlPanel.symmetry.vertical   -pady 5
	grid .controlPanel.symmetry.horizontal -pady 5
	grid .controlPanel.symmetry.diagonal   -pady 5
	
	
	#dump
	ttk::button .controlPanel.dump     -text "Dump"      -command { dumpPixelmap }
	grid .controlPanel.dump     -row 100 -column 0 -pady $buttonsPaddingY
	
}



buildGui


bind . <KeyPress-Up>    { focusUp    }
bind . <KeyPress-Left>  { focusLeft  }
bind . <KeyPress-Down>  { focusDown  }
bind . <KeyPress-Right> { focusRight }

 , ,

u5er
()

В каком формате вы пишете документацию к своим проектам?

Форум — Development

Интересуюсь потому, что сам подумываю начать писать полноценную. Вопрос задан не в контексте «какие варианты возможны», а в контексте «какие варианты реально используются».

Сам пока поглядываю в сторону markdown, т.к. в нём в нём есть подсветка и можно вставлять картинки. Иногда в этом есть необходимость, т.к. они нагляднее, чем псевдографика.

 

u5er
()

Написал эмулятор своего мобильника

Галерея — Скриншоты

Более чем два месяца назад заказал отладочные платы для своего хоббийного проекта, но они так и не пришли и хз, придут ли вообще. Разработка прошивки для него из-за этого застопорилась: писать «на воздух» я не особо люблю, а текущая клавиатура уже не отвечает моим требованиям - банально не хватает кнопок.

И тогда в голову начала приходить мысль - а не организовать ли мне эмулятор по типу того, который используется в Android Studio? Идея показалась мне классной, но останавливало отсутствие внятной документации по qemu, поэтому для реализации задумки предлагалось соснуть сурца. В какой-то момент я понял, что без полноценной клавиатуры я не смогу продолжить проект - банально нет всех нужных кнопок - было принято решение засучить рукава и попробовать.

В штатной поставке esp-idf есть qemu, но в ней особо не развернёшься, поэтому начал с простого - используя простое i2c устройство в качестве шаблона, создал заглушки для клавиатуры, контроллера модема и контроллера питания. Подключить их тоже не составило труда - код как раз на скриншоте. Обмен данными по шине i2c оказался очень простым: на эмулируемом устройстве есть всего 2 функции обратного вызова - для чтения и для записи. Таким образом, когда мастер пишет и читает, то просто подсовываем ему то, что он просит. Таким образом реализовать эмуляцию i2c устройств оказалось легче лёгкого.

Далее прерывания. Для эмуляции линий gpio в qemu используются линии прерываний. Тут вроде всё просто: на эмулируемом устройстве создаются выходные линии qemu_irq и далее они подключаются… куда? Вот тут меня ждала первая, пусть и лёгкая, задача. В самом начале я подключил линию irq клавиатуры на матрицу прерываний. Обработчик прерываний вызывался, но понять, на каком gpio оно произошло он не мог. Немного пораскинув мозгами и пососав сурца покопав исходники, я нашёл правильное место для подключения - матрица gpio. Как видите, в функциях read и write ничего нет, поэтому реализовать матрицу предлагается самостоятельно. Ожидаемо :) Реализовывается она очень просто. Сначала в матрице gpio создаются 40 входных и 40 выходных лини qemu_irq, которые будут отвечать за все gpio, которые есть у esp32. Далее создаются ещё 2 выходные линии qemu_irq, которые отвечают за обычные и non-maskable прерывания. Их я подключил к матрице прерываний на специально предусмотренные для этого каналы.

Теперь возвращаемся к функцуиям read и write. Вы когда-нибудь работали с расширителями портов, которые подключаются по шинам spi и i2c? Вся суть сводится к тому, что вы просто пишете и читаете нужные регистры по шинам, верно? Вот тут всё тоже самое, только с одним маленьким отличием - сами регистры нахадятся в самом микроконтроллере и процессор имеет к ним прямой доступ. То есть матрица gpio - это просто расширитель портов, который встроен в процессор и подключен напрямую к нему. Таким образом, вы теперь выступаете в качестве микросхемы :) В ваши регистры будут что-то писать и читать, а вы будете управлять линиями gpio. Когда процессор хочет выставить нужный gpio в нужный уровень - он просто пишет нужный бит в нужный регистр. Вы это видите и переключаете нужную линию qemu_irq в нужный уровень. Если же входная линия изменяет свой уровень, то вы просто отмечаете это у себя в структуре и при чтении сможете вернуть процессору текущие уровни gpio. Если процессор настроил прерывание на каком-либо gpio, то его можно уведомить об этом с помощью линий irq и nmi-irq. Далее процессор прочитает регистр прерываний и попросит вас сбросить их и вы это сделаете :) (иначе он будет постоянно опрашивать регистры прерываний, думая, что они всё ещё активны). Таким образом, реализовать матрицу gpio не составило особого труда. После этого я подключил свои устройства к нужным линиям матрицы gpio и смог эмулировать работу gpio без проблем.

Итак, я уже потирал руки и думал: «Сейчас я кабанчиком организую эмуляцию дисплея на шине spi и можно будет браться за гуй.». Ок, по аналогии с устройством i2c, беру в качестве шаблона какое-нибудь spi-устройство и начинаю реализовывать дисплей. Общение происходит как по i2c, только вместо обратных вызовов read и write, у вас есть обратный вызов transfer, в котором одновременно происходит и приём и передача данных. Сделал я дисплей, запускаю и… тишина! То есть по шине мне передаются сплошные нули! Всмысле? 0_0 В этот раз пососать сурца покопаться в исходниках пришлось гораздо более основательно. В итоге, понатыкав везде и всюду спасительный printf(), я нашёл чёрную дыру, в которой терялись данные по дороге от гостя до эмулируемого дисплея. На первый взгляд кажется, что тут всё ок, но когда я расставил printf() для распечатки адресов регистров, которые пишет и читает процессор, то всё встало на свои места - этот код никаким образом не обрабатывает регистры DMA! То есть вообще. Получается, что гость пытается слать данные через DMA буфер, а ванильный эмулятор spi туда даже не смотрит. В итоге, я сделал его копию и написал свою реализацию, которая позволяет отправлять данные по spi с использованием dma (полную реализацию пилить не стал, ибо влом). И для этого пришлось решить задачу со звёздочкой - доступ к памяти гостя.

Пару слов о том, как работает DMA на esp32. Прошивка организовывает где-нибудь в памяти специальные структуры с указателями на сами данные и входной буфер. Далее в специальнные DMA-регистры записываются адреса (указатели) этих структур. Далее подаётся команда на запуск передачи и данные передаются/принимаются без участия процессора. Теперь передо мной встала задача - как получить доступ по указателям, которые мне передаёт гость? Ведь гость даёт адрес внутри адресного пространства виртуальной машины. Сначала я нашёл решение с помощью функций cpu_physical_memory_read() и cpu_physical_memory_write(), которые работают с указателями из адресного пространства гостя. Но лишнее копирование не давало мне покоя и я нашёл решение получше.

При создании виртуальной машины qemu создаются различные области памяти. Одна из них - оперативка. Создаётся с помощью memory_region_init_ram(). В esp32 создаётся несколько различных областей такого типа. Фишка в том, что все эти области выделены как обычная память на хосте. Идея заключается в том, чтоб использовать memory_region_get_ram_ptr(), чтоб получить указатель на каждую область. Затем, зная начальный и конечный адрес каждого региона, можно вычислить расположение данных в оперативке хоста и работать с ними напрямую.

Последняя задача - как передать эти указатели, которые возвращают вызовы memory_region_get_ram_ptr(), в сам эмулятор spi? Он выполнен как отдельное устройство. В этот раз сосание сурца ковыряние в исходниках и чтение крох документации ничего не дали, поэтому решил действовать в лоб - передавать через свойства устройства. В эмуляторе spi я сделал несколько свойств с помощью object_property_add(), при создании машины при инициализации spi просто передал указатели как uint64_t с помощью qdev_prop_set_uint64(). Не уверен, что поступал правильно, но других решений не нашёл. Возможно, в таких случаях следует создавать отдельное устройство - эмулятор DMA, не знаю. Тем не менее, это сработало - я смог получить доступ к памяти гостя, высчитав смещение и прибавив его к одному из указателей на область памяти.

Гуй сделал на Tcl/Tk. Общение в машиной идёт через fifo. Просто и понятно. Уверен, что у qemu есть свой api для построения гуя, но я, честно говоря, к этому моменту уже окончательно устал искать информацию раз, и хотелось немного попрактиковаться в тикле два. До этого в тикле не работал с цветными изображениями и это был неплохой повод попробовать. Оказалось, что всё делается элементарно через image. Благо по тиклю информация есть, в отличие от.

К чему я вообще пишу обо всё об этом? Похвастаться? Да, не без этого, но ещё больше хочется поделиться вот чем. До того, как я полез писать эмулятор, я многое знал, но не понимал как именно работают те или иные вещи в микроконтроллерах. После того, как я написал эмулятор, я многое понял. Например, как именно процессор управляет своей перефирией. Как работают прерывания. Как работает DMA. Да и вообще, получил опыт в работе с «сырыми» регистрами. Я это к тому, что если у вас есть какая-нибудь идея и вам хочется её осуществить, то всегда пробуйте! Даже если задача изначально кажется сложной и неподъёмной. Запросто может оказаться так, что вы, как и я, не просто реализуете задуманное, но ещё получите ценные знания и/или опыт в процессе.

Такие дела \ё/

 , ,

u5er
()

Посоветуйте литературу по программированию qemu

Форум — Development

Хочется почитать что-то вроде «Linux Device Drivers», но только для qemu. Хочу эмулировать свою кастомную плату с произвольной периферией, поэтому ищу «обзорную» информацию с объяснением общих принципов написания кода для qemu.

 , ,

u5er
()

Переносимость спецификаторов функций *printf

Форум — Development

Есть некий код

uint32_t value;
...
printf( "FATAL: Unknown security result: %u\n", value );

Под одну архитектуру это собирается без ошибок. Под другую сборка падает с ошибкой вида

format '%u' expects argument of type 'unsigned int', but argument 2 has type 'uint32_t' {aka 'long unsigned int'}

Как быть в случаях, когда подобный код должен собираться под разные архитектуры? Заворачивать всё в препроцессор или засучить рукава и писать свою нестандартную библиотеку си?

 ,

u5er
()

Какие функции для работы с файлами на си вы предпочитаете?

Форум — Development

И почему?

Те, которые работают с fd, или те, которые работают с FILE.

Чисто из любопытства.

 

u5er
()

Мой процесс велосипедостроения

Галерея — Скриншоты

Решил поделиться тем, как я изобретаю свой ляс изучаю устройство различных форматов изображений и алгоритмов сжатия в процессе ожидания заказанных мою плат.

Конкретно на данном скрине я костылю изучаю png-zlib-deflate. Получается довольно неплохо. По крайней мере, я наконец-таки понял, как работает алгоритм Хаффмана. До этого было представление в лишь общих чертах.

( читать дальше... )

 ,

u5er
()

А существуют ли в открытом доступе тесты для алгоритмов?

Форум — Development

Допустим, я решил реализовать какой-нибудь алгоритм. Например, декодер ogg, распаковщик gzip или ещё что-нибудь. Я полез читать документацию и писать код. Допустим, код не работает и я не знаю, где я допустил ошибку. Как правило, в документации описаны операции, которые нужно совершить над входными данными, а вот с примерами прям совсем туго.

Есть ли наборы тестов, которые содержат некие «референсные» данные, которые должны получаться после каждой операции? Для того, чтоб можно было ввести заранее известные данные, которые на каждом этапе в программе будут давать заранее известный результат, чтоб можно было найти то место в программе, где код написан с ошибкой. Если кто знает, поделитесь ссылками, пожалуйста.

u5er
()

Напоминание о необходимости отключать вентиляторы охлаждения при продувке от пыли

Форум — Talks

Не так давно купил себе салазки для жёстких дисков в отсек 5.25. В них есть вентилятор охлаждения и кнопка для отключения диска. Когда я отключаю диск кнопкой, то светодиод-индикатор питания светится в «полнакала» ещё полсекунды. Суть в том, что вентилятор будет работать как генераор, если его раскрутить.

Суть в том, что если его очень сильно раскрутить, например, сжатым воздухом при продувке, то он может выдать выдать напряжение больше своего номинала со всеми вытекающими.

Довольно давно читал в сети истории об убитых материнках при продувке воздухом. В них как раз описывался этот эффект. Теперь воочую убедился в этом сам и держу в курсе :)

 

u5er
()

Как добавить диск в steam, если он не добавляется через настройки.

Форум — Games

На статью не тянет, но с этой проблемой сталкиваются часто, поэтому решил вкинуть немного полезной инфы, чтоб она была в рускоязычном сегменте сети.

Форматируете диск желательно в линуксовую файловую систему. Не используйте ntfs или fat32, иначе рискуете огрести проблем. Организовываете его постоянное монтирование. Монтирование должно выполняться без опции noexec, потому что для работы требуются права на выполнение. Для примера мы будем считать, что диск смонтирован /media/disk0.

Далее в /media/disk0 создаёте новую директорию, в которой будет библиотека стима. Для примера мы будем считать, что директория называется steamlib. Далее назначем владельцем этой директории того пользователя, который будет пользоваться этой библиотекой.

Теперь выключаем стим. В домашнем каталоге ищем файл libraryfolders.vdf по пути .steam/steam/steamapps. Открываем его текстовым редактором.

Вот его основной синтаксис:

"libraryfolders"
{
	"0"
	{
		"path"		"/media/hdd0/steam/.local/share/Steam"
		"label"		""
	}
	"1"
	{
		"path"		"/media/ssd0/steam/library"
		"label"		""
	}
}

Открыв реальный файл, вы увидите, что он несколько отличается: в нём есть гораздо больше информации, чем я привёл, но это не должно вас сбить с толку, поскольку вся остальная информация добавляется стимом динамически.

Уже на данном этапе должно быть понятно, что нужно сделать - дописать в файл путь до новой директории с библиотекой стим по аналогии с тем, что там уже есть. Пишете двойные кавычки и число в них на единицу больше от того, что в предыдущих двойных кавычках. Далее блок из фигурных скобок с полями path и label. label оставляете пустым, а в path прописываете путь до нового диска. В нашем случае это будет примерно так:

"libraryfolders"
{
	"0"
	{
		"path"		"/media/hdd0/steam/.local/share/Steam"
		"label"		""
	}
	"1"
	{
		"path"		"/media/ssd0/steam/library"
		"label"		""
	}
	"2"
	{
		"path"		"/media/disk0/steamlib"
		"label"		""
	}
}

Сохраняете изменения, запускаете стим. Больше ничего делать не нужно - новая директория уже будет доступна в библиотеке стима.

Еще один нюанс есть:

При ручном добавлении автоматически не будет создана /media/ssd0/steam/library/steamapps, из-за чего при попытке поставить игру на такой диск стим выгрунется ошибкой записи (хотя перенос игры через стим сработает и создаст эту директорию).

 

u5er
()

Почему удалили тему?

Форум — Linux-org-ru

https://www.linux.org.ru/forum/general/17938729

Пользователя забанить - это одно, но в самой теме вроде нет никаких нарушений.

Чисто из любопытства интересуюсь.

 

u5er
()

tk scaling игнорируется

Форум — Development

Что бы я туда не прописывал - визуально ничего не меняется. Есть идеи, почему это может быть так?

Версия 8.6.14_1.

 

u5er
()

Нелогичная логика

Форум — Development

Куприв!

Пишу я тут очередной ляс и в процессе компиляции компилятор и даже линковщик(!) выдаёт мне такие предупреждения:

cc -Wall -O2   -c -o sim7600-at.o sim7600-at.c
sim7600-at.c: In function 'simApplicationToolkit':
sim7600-at.c:1013:17: warning: implicit declaration of function 'gets'; did you mean 'fgets'? [-Wimplicit-function-declaration]
 1013 |                 gets( userAns );
      |                 ^~~~
      |                 fgets
cc -s  sim7600-at.o utils_pdu_sms.o   -o sim7600-at
/usr/bin/ld: sim7600-at.o: in function `simApplicationToolkit':
sim7600-at.c:(.text+0xf91): warning: the `gets' function is dangerous and should not be used.

Справедливо, но тогда почему нет подобного предупреждения при использовани strncpy, например, которая тоже дырявая, даже не смотря на n?

 

u5er
()

Вопрос по настройке полосы прокрутки gtk

Форум — Desktop

В приложениях, которые используют gtk, есть одна особенность. Если навести мышь на полосу прокрутки, зажать левую кнопку мыши и подержать пару секунд, то при перетаскивании ползунка мышью он перетаскивается с отставанием от мыши. Таким образом не получится перетащить его до конца.

Смотрел документацию.
https://docs.gtk.org/gtk3/class.Settings.html#properties
https://docs.gtk.org/gtk4/class.Settings.html#properties
Но не нашёл там подходящих настроек.

Каким образом можно отключить такое поведение?

 

u5er
()

uBlock Origin в хроме уже всё, а божья коровка ещё не готова

Форум — Talks

https://www.opennet.ru/opennews/art.shtml?num=62859

Высад. Придётся теперь косплеить терпилу на мозиле до тех пор, пока не появится адекватный браузер.

 

u5er
()

Кто-нибудь из форумчан на практике сталкивался с ошибкой при работе sprintf()?

Форум — Development

Вопрос в заголовке. Если да, то распишите подробности. В манах пишут про отрицательное значение при ошибке, но списка errno нет.

Вопрос снят. Судя по ответам в теме и поиску в сети, есть смысл избегать следующих функций в критически важном коде: printf(), fprintf(), dprintf(), sprintf(), snprintf(), vprintf(), vfprintf(), vdprintf(), vsprintf(), vsnprintf(). Эти функции имеют общую man-страницу printf(3) и в ней указано, что эти функции могут завершаться с ошибкой, но при этом не приводится списка возможных ошибок, поэтому невозможно предусмотреть ошибки заранее.

 

u5er
()

Отрыгнула клавиатура - как такое возможно?

Форум — Talks

Сидел играл в погремушки. Наигрался. Закрыл игру и ушёл примерно на час, оставив комп включённым. Прихожу, патаюсь запустить браузер, а он не запускается. Пытаюсь вообще что-либо следать с клавиатуры - ничего не происходит. Вначале подумал, что зависла система, но курсор мыши двигается и на фоне хрустят блины - работает торрент. Перезагрукзка не помогла. Опытным путём выяснил, что клавиатура оглохла. Причём подсветка на ней работает, а сама клава даже в системе не видна.

Поделитесь опытом - у кого-нибудь вот так запросто умирали клавы?

u5er
()

Как организовать автовыгрузку из свопа?

Форум — Desktop

Ситуация следующая. Запускается программа А, которая занимает какую-то часть памяти. Запускается программа Б, которой не хватает оставшейся свободной памяти, поэтому программа А отправляется в своп. После закрытия программы Б, программа А остаётся в свопе и из-за этого люто тормозит. Приходится делать swapoff -a и swapon -a чтоб вернуть прежнюю отзывчивость.

Вопрос: есть ли способы настроить поведение таким образом, чтоб при освобождении памяти система автоматически доставала данные из свопа не дожидаясь момента, когда они понадобятся?

 

u5er
()

RSS подписка на новые темы