parent
1ef6c5abe4
commit
1377f55cd2
@ -0,0 +1,14 @@ |
||||
DIRS = doc man scripts src
|
||||
|
||||
all: |
||||
set -e; for d in $(DIRS); do $(MAKE) -C $$d ; done
|
||||
|
||||
clean: |
||||
set -e; for d in $(DIRS); do $(MAKE) -C $$d clean ; done
|
||||
|
||||
install: |
||||
set -e; for d in $(DIRS); do $(MAKE) -C $$d install ; done
|
||||
|
||||
tags: |
||||
ctags -R
|
||||
|
@ -0,0 +1,11 @@ |
||||
|
||||
include ../config.mk |
||||
|
||||
all: |
||||
@echo "Nothing to do..."
|
||||
|
||||
install: |
||||
@echo "Nothing to do..."
|
||||
|
||||
clean: |
||||
@echo "Nothing to do..."
|
@ -0,0 +1,96 @@ |
||||
/* [filename]: [one line description of the file]
|
||||
* -------------------------------------------------------------------- |
||||
* |
||||
* Linux WLAN
|
||||
* |
||||
* The contents of this file are subject to the Mozilla Public |
||||
* License Version 1.0 (the "License"); you may not use this file |
||||
* except in compliance with the License. You may obtain a copy of |
||||
* the License at http://www.mozilla.org/MPL/
|
||||
* |
||||
* Software distributed under the License is distributed on an "AS |
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or |
||||
* implied. See the License for the specific language governing |
||||
* rights and limitations under the License. |
||||
* |
||||
* The initial developer of the original code is Mark S. Mathews |
||||
* <mark@absoval.com>. Portions created by Mark S. Mathews |
||||
* are Copyright (C) 1998 AbsoluteValue Software, Inc. All Rights Reserved. |
||||
*
|
||||
* -------------------------------------------------------------------- |
||||
* |
||||
* The initial author may be reached as mark@absoval.com, or
|
||||
* C/O AbsoluteValue Software Inc., P.O. Box 941149,
|
||||
* Maitland, FL, 32794-1149 |
||||
* |
||||
* -------------------------------------------------------------------- |
||||
* |
||||
* [File Description] |
||||
* |
||||
* [Implementation and Usage Notes]
|
||||
* |
||||
* -------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
/*================================================================*/ |
||||
/* System Includes */ |
||||
|
||||
|
||||
/*================================================================*/ |
||||
/* Project Includes */ |
||||
|
||||
|
||||
/*================================================================*/ |
||||
/* Local Constants */ |
||||
|
||||
|
||||
/*================================================================*/ |
||||
/* Local Macros */ |
||||
|
||||
|
||||
/*================================================================*/ |
||||
/* Local Types */ |
||||
|
||||
|
||||
/*================================================================*/ |
||||
/* Local Static Definitions */ |
||||
|
||||
/*----------------------------------------------------------------*/ |
||||
/* --A subsection */ |
||||
|
||||
|
||||
/*================================================================*/ |
||||
/* Local Function Declarations */ |
||||
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* [function name] |
||||
* |
||||
* [Description] |
||||
* |
||||
* Arguments: |
||||
* [arglist] |
||||
* |
||||
* Returns:
|
||||
* [retlist] |
||||
* |
||||
* Side effects: |
||||
* [desc] |
||||
* |
||||
* Call context: |
||||
* [desc] |
||||
----------------------------------------------------------------*/ |
||||
int afunction(void) |
||||
{ |
||||
DBFENTER; |
||||
|
||||
if ( a ) { |
||||
prinf("xxx"); |
||||
} |
||||
|
||||
|
||||
DBFEXIT; |
||||
return 0; |
||||
} |
||||
|
||||
|
@ -0,0 +1,311 @@ |
||||
<HTML> |
||||
<HEAD> |
||||
<TITLE>AVS C Source file format</TITLE> |
||||
</HEAD> |
||||
<BODY> |
||||
<H1>1. C Source file format</H1> |
||||
<P> |
||||
The following defines the common C source file format for linux-wlan. |
||||
Most of the C-code formatting rules come from the linux kernel |
||||
document <CODE>CodingStyle</CODE>. |
||||
|
||||
<H1>2. Characters and Code layout</H1> |
||||
<H2>2.1. Character Set</H2> |
||||
<P> |
||||
For all source files, we'll stick to the US character set and avoid all |
||||
trigraphs. |
||||
|
||||
<H2>2.2. Indentation</H2> |
||||
<P> |
||||
All indentation will be done using tab characters which are mapped to a |
||||
spacing of eight characters. |
||||
|
||||
<H2>2.3. Braces</H2> |
||||
<P> |
||||
Braces will be placed according to the format originally established |
||||
in Kernighan and Ritchie's book "The C Programming Language". Here |
||||
are some example statements: |
||||
<P> |
||||
<TABLE border=1><TR><TD><PRE> |
||||
|
||||
for ( i= 0; i < N; i++) { |
||||
. |
||||
. |
||||
. |
||||
} |
||||
|
||||
if ( a < b ) { |
||||
. |
||||
. |
||||
. |
||||
} else { |
||||
. |
||||
. |
||||
. |
||||
} |
||||
|
||||
do { |
||||
. |
||||
. |
||||
. |
||||
} while ( i >> 0 ); |
||||
</PRE></TABLE> |
||||
|
||||
|
||||
|
||||
<H1>3. Naming and Definition Conventions</H1> |
||||
|
||||
<H2>3.1. Preprocessor Elements</H2> |
||||
<P> |
||||
All elements defined via the C preprocessor (constants and macros) are |
||||
named using all capital letters. An exception is for macros that are |
||||
either wrapping function calls for portability or for macros that are |
||||
inline replacements for code that would normally be in a function. |
||||
|
||||
<H2>3.2. Types</H2> |
||||
<P> |
||||
All programmer defined types must have single word type names |
||||
defined using the <PRE>typedef</PRE> statement. All type names |
||||
should be identified with an <PRE>_t</PRE> suffix. This is |
||||
particularly important for function pointers that are members of |
||||
structures or arguments to functions. |
||||
|
||||
<P> |
||||
Anonymous types are not allowed. All struct, union, and enum |
||||
types shall be named and typedef'd. |
||||
|
||||
|
||||
<H2>3.3. Variables</H2> |
||||
The following conventions should be followed for variable |
||||
declaration and naming: |
||||
<UL> |
||||
<LI>Variables should be named using meaningful names. |
||||
<LI>Avoid variables with static lifetimes. |
||||
<LI>If static lifetime variables must be used, use file |
||||
scoped static variables and avoid static lifetime |
||||
variables with visibility beyond file scope. |
||||
<LI>All static lifetime variables should be declared in |
||||
the "Local Statics" section near the top of a given |
||||
source file. |
||||
</UL> |
||||
|
||||
<H2>3.4. Functions</H2> |
||||
The following conventions should be followed for function |
||||
declaration and definition: |
||||
<UL> |
||||
<LI><B>All</B> functions must be declared above the point |
||||
where they are called. |
||||
<LI>Any functions that are only intended to be called |
||||
within a given source file should be declared static |
||||
within that file. |
||||
<LI>Functions defined within a common source file that are |
||||
visible across source file boundaries should be named |
||||
using a prefix that is unique to that source file. |
||||
</UL> |
||||
|
||||
<H1>4. File Layout</H1> |
||||
<P> |
||||
Each file should be layed out using a common format. The |
||||
following shows a complete file with all its major sections. |
||||
|
||||
<P> |
||||
Each major section within the file is begun with a comment of the |
||||
form: |
||||
<PRE> |
||||
/*================================================================*/ |
||||
/* [Section Name] */ |
||||
</PRE> |
||||
|
||||
<P> |
||||
Subsections within a major section are denoted using: |
||||
<PRE> |
||||
/*----------------------------------------------------------------*/ |
||||
/* [Subsection Name] */ |
||||
</PRE> |
||||
|
||||
<P> |
||||
<TABLE border=1><TR><TD> |
||||
<PRE> |
||||
/* [filename]: [one line description of the file] |
||||
* -------------------------------------------------------------------- |
||||
* |
||||
* [Project Name] |
||||
* |
||||
* [License Statement] |
||||
* |
||||
* [Warranty Statement] |
||||
* |
||||
* [Initial Author Statement] |
||||
* |
||||
* -------------------------------------------------------------------- |
||||
* |
||||
* [Initial Author Contact] |
||||
* |
||||
* -------------------------------------------------------------------- |
||||
* |
||||
* [File Description] |
||||
* |
||||
* [Implementation and Usage Notes] |
||||
* |
||||
* -------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
/*================================================================*/ |
||||
/* System Includes */ |
||||
|
||||
|
||||
/*================================================================*/ |
||||
/* Project Includes */ |
||||
|
||||
|
||||
/*================================================================*/ |
||||
/* Local Constants */ |
||||
|
||||
|
||||
/*================================================================*/ |
||||
/* Local Macros */ |
||||
|
||||
/*----------------------------------------------------------------*/ |
||||
/* [A subsection] */ |
||||
|
||||
/*================================================================*/ |
||||
/* Local Types */ |
||||
|
||||
|
||||
/*================================================================*/ |
||||
/* Local Static Definitions */ |
||||
|
||||
|
||||
/*================================================================*/ |
||||
/* Local Function Declarations */ |
||||
|
||||
|
||||
/*================================================================*/ |
||||
/* Function Definitions */ |
||||
|
||||
</PRE> |
||||
</TABLE> |
||||
|
||||
<H2>4.1. System Includes Section</H2> |
||||
<P> |
||||
Preprocessor <CODE>#include</CODE> statements that are including |
||||
<I>system</I> includes shall be placed in this section. System |
||||
includes are those include files that are <B>not</B> part of the |
||||
managed source for this project. |
||||
|
||||
<H2>4.2. Project Includes Section</H2> |
||||
<P> |
||||
Preprocessor <CODE>#include</CODE> statements that are including |
||||
<I>project</I> includes shall be placed in this section. Project |
||||
includes are those include files that are a part of the |
||||
managed source for this project. |
||||
|
||||
<H2>4.3. Local Constants Section</H2> |
||||
<P> |
||||
Preprocessor "manifest" constants that are local to this file shall be |
||||
placed in this section. "Manifest" constants are preprocessor macros |
||||
that take no arguments. |
||||
|
||||
<H2>4.4. Local Macros Section</H2> |
||||
<P> |
||||
Proprocessor macros that accept arguments shall be placed in this |
||||
section. |
||||
|
||||
<H2>4.5. Local Types Section</H2> |
||||
<P> |
||||
Programmer defined types that are only used within the scope of this |
||||
file shall be defined in this section. Programmer defined types that |
||||
are used in more than one source file should be defined in a header |
||||
file. |
||||
|
||||
<H2>4.6. Local Static Definitions Section</H2> |
||||
<P> |
||||
Variables with static extent that are defined within this file shall |
||||
be placed in this section. Whether a variable has scope beyond this |
||||
file will be apparent based on the presence or absence of the |
||||
<CODE>static</CODE> keyword in the declaration. If a variable is |
||||
declared without the <CODE>static</CODE> keyword, there should be an |
||||
<CODE>extern</CODE> declaration for that variable in a header file. |
||||
|
||||
<H2>4.6. Local Function Declarations Section</H2> |
||||
<P> |
||||
Functions that are only used within this file should be declared |
||||
(prototyped) in this section. Additionally, these functions should be |
||||
declared using the <CODE>static</CODE> keyword. This avoids polluting |
||||
the global namespace with function names that need not be |
||||
<CODE>extern</CODE>. |
||||
|
||||
<P> |
||||
Any functions defined in this file that <I>are</I> called from outside |
||||
this file should be declared (prototyped) in a header file. |
||||
|
||||
<H2>4.6. Function Definitions Section</H2> |
||||
<P> |
||||
This section contains the definitions of the functions in this file. |
||||
Each function (or group of strongly related functions) will be |
||||
preceded by a function header comment (see below). |
||||
|
||||
<H1>5. Comments</H1> |
||||
<H2>5.1. File Header</H2> |
||||
<P> |
||||
Each source file will have a header comment containing information |
||||
about the file as a whole. That comment shall be formatted: |
||||
<P> |
||||
<TABLE border=1><TR><TD><PRE> |
||||
/* [filename]: [one line description of the file] |
||||
* -------------------------------------------------------------------- |
||||
* |
||||
* [Project Name] |
||||
* |
||||
* [License Statement] |
||||
* |
||||
* [Warranty Statement] |
||||
* |
||||
* [Initial Author Statement] |
||||
* |
||||
* -------------------------------------------------------------------- |
||||
* |
||||
* [Initial Author Contact] |
||||
* |
||||
* -------------------------------------------------------------------- |
||||
* |
||||
* [File Description] |
||||
* |
||||
* [Implementation and Usage Notes] |
||||
* |
||||
* -------------------------------------------------------------------- |
||||
*/ |
||||
</PRE> |
||||
</TABLE> |
||||
|
||||
<H2>5.2. Function Header</H2> |
||||
<P> |
||||
Each function (or group of closely related functions) will be preceded |
||||
by a function comment header. The <CODE>Side effects</CODE> and |
||||
<CODE>Call context</CODE> sections are optional. |
||||
<P> |
||||
<TABLE border=1><TR><TD><PRE> |
||||
/*---------------------------------------------------------------- |
||||
* [function name] |
||||
* |
||||
* [description] |
||||
* |
||||
* Arguments: |
||||
* [argument list] |
||||
* |
||||
* Returns: |
||||
* [return value list] |
||||
* |
||||
* Side effects: |
||||
* [description of function side effects] |
||||
* |
||||
* Call context: |
||||
* [description of calling context] |
||||
----------------------------------------------------------------*/ |
||||
</PRE> |
||||
</TABLE> |
||||
|
||||
|
||||
</BODY> |
||||
</HTML> |
||||
|
@ -0,0 +1,212 @@ |
||||
|
||||
Linux kernel coding style |
||||
|
||||
This is a short document describing the preferred coding style for the |
||||
linux kernel. Coding style is very personal, and I won't _force_ my |
||||
views on anybody, but this is what goes for anything that I have to be |
||||
able to maintain, and I'd prefer it for most other things too. Please |
||||
at least consider the points made here. |
||||
|
||||
First off, I'd suggest printing out a copy of the GNU coding standards, |
||||
and NOT read it. Burn them, it's a great symbolic gesture. |
||||
|
||||
Anyway, here goes: |
||||
|
||||
|
||||
Chapter 1: Indentation |
||||
|
||||
Tabs are 8 characters, and thus indentations are also 8 characters. |
||||
There are heretic movements that try to make indentations 4 (or even 2!) |
||||
characters deep, and that is akin to trying to define the value of PI to |
||||
be 3. |
||||
|
||||
Rationale: The whole idea behind indentation is to clearly define where |
||||
a block of control starts and ends. Especially when you've been looking |
||||
at your screen for 20 straight hours, you'll find it a lot easier to see |
||||
how the indentation works if you have large indentations. |
||||
|
||||
Now, some people will claim that having 8-character indentations makes |
||||
the code move too far to the right, and makes it hard to read on a |
||||
80-character terminal screen. The answer to that is that if you need |
||||
more than 3 levels of indentation, you're screwed anyway, and should fix |
||||
your program. |
||||
|
||||
In short, 8-char indents make things easier to read, and have the added |
||||
benefit of warning you when you're nesting your functions too deep. |
||||
Heed that warning. |
||||
|
||||
|
||||
Chapter 2: Placing Braces |
||||
|
||||
The other issue that always comes up in C styling is the placement of |
||||
braces. Unlike the indent size, there are few technical reasons to |
||||
choose one placement strategy over the other, but the preferred way, as |
||||
shown to us by the prophets Kernighan and Ritchie, is to put the opening |
||||
brace last on the line, and put the closing brace first, thusly: |
||||
|
||||
if (x is true) { |
||||
we do y |
||||
} |
||||
|
||||
However, there is one special case, namely functions: they have the |
||||
opening brace at the beginning of the next line, thus: |
||||
|
||||
int function(int x) |
||||
{ |
||||
body of function |
||||
} |
||||
|
||||
Heretic people all over the world have claimed that this inconsistency |
||||
is ... well ... inconsistent, but all right-thinking people know that |
||||
(a) K&R are _right_ and (b) K&R are right. Besides, functions are |
||||
special anyway (you can't nest them in C). |
||||
|
||||
Note that the closing brace is empty on a line of its own, _except_ in |
||||
the cases where it is followed by a continuation of the same statement, |
||||
ie a "while" in a do-statement or an "else" in an if-statement, like |
||||
this: |
||||
|
||||
do { |
||||
body of do-loop |
||||
} while (condition); |
||||
|
||||
and |
||||
|
||||
if (x == y) { |
||||
.. |
||||
} else if (x > y) { |
||||
... |
||||
} else { |
||||
.... |
||||
} |
||||
|
||||
Rationale: K&R. |
||||
|
||||
Also, note that this brace-placement also minimizes the number of empty |
||||
(or almost empty) lines, without any loss of readability. Thus, as the |
||||
supply of new-lines on your screen is not a renewable resource (think |
||||
25-line terminal screens here), you have more empty lines to put |
||||
comments on. |
||||
|
||||
|
||||
Chapter 3: Naming |
||||
|
||||
C is a Spartan language, and so should your naming be. Unlike Modula-2 |
||||
and Pascal programmers, C programmers do not use cute names like |
||||
ThisVariableIsATemporaryCounter. A C programmer would call that |
||||
variable "tmp", which is much easier to write, and not the least more |
||||
difficult to understand. |
||||
|
||||
HOWEVER, while mixed-case names are frowned upon, descriptive names for |
||||
global variables are a must. To call a global function "foo" is a |
||||
shooting offense. |
||||
|
||||
GLOBAL variables (to be used only if you _really_ need them) need to |
||||
have descriptive names, as do global functions. If you have a function |
||||
that counts the number of active users, you should call that |
||||
"count_active_users()" or similar, you should _not_ call it "cntusr()". |
||||
|
||||
Encoding the type of a function into the name (so-called Hungarian |
||||
notation) is brain damaged - the compiler knows the types anyway and can |
||||
check those, and it only confuses the programmer. No wonder MicroSoft |
||||
makes buggy programs. |
||||
|
||||
LOCAL variable names should be short, and to the point. If you have |
||||
some random integer loop counter, it should probably be called "i". |
||||
Calling it "loop_counter" is non-productive, if there is no chance of it |
||||
being mis-understood. Similarly, "tmp" can be just about any type of |
||||
variable that is used to hold a temporary value. |
||||
|
||||
If you are afraid to mix up your local variable names, you have another |
||||
problem, which is called the function-growth-hormone-imbalance syndrome. |
||||
See next chapter. |
||||
|
||||
|
||||
Chapter 4: Functions |
||||
|
||||
Functions should be short and sweet, and do just one thing. They should |
||||
fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24, |
||||
as we all know), and do one thing and do that well. |
||||
|
||||
The maximum length of a function is inversely proportional to the |
||||
complexity and indentation level of that function. So, if you have a |
||||
conceptually simple function that is just one long (but simple) |
||||
case-statement, where you have to do lots of small things for a lot of |
||||
different cases, it's OK to have a longer function. |
||||
|
||||
However, if you have a complex function, and you suspect that a |
||||
less-than-gifted first-year high-school student might not even |
||||
understand what the function is all about, you should adhere to the |
||||
maximum limits all the more closely. Use helper functions with |
||||
descriptive names (you can ask the compiler to in-line them if you think |
||||
it's performance-critical, and it will probably do a better job of it |
||||
that you would have done). |
||||
|
||||
Another measure of the function is the number of local variables. They |
||||
shouldn't exceed 5-10, or you're doing something wrong. Re-think the |
||||
function, and split it into smaller pieces. A human brain can |
||||
generally easily keep track of about 7 different things, anything more |
||||
and it gets confused. You know you're brilliant, but maybe you'd like |
||||
to understand what you did 2 weeks from now. |
||||
|
||||
|
||||
Chapter 5: Commenting |
||||
|
||||
Comments are good, but there is also a danger of over-commenting. NEVER |
||||
try to explain HOW your code works in a comment: it's much better to |
||||
write the code so that the _working_ is obvious, and it's a waste of |
||||
time to explain badly written code. |
||||
|
||||
Generally, you want your comments to tell WHAT your code does, not HOW. |
||||
Also, try to avoid putting comments inside a function body: if the |
||||
function is so complex that you need to separately comment parts of it, |
||||
you should probably go back to chapter 4 for a while. You can make |
||||
small comments to note or warn about something particularly clever (or |
||||
ugly), but try to avoid excess. Instead, put the comments at the head |
||||
of the function, telling people what it does, and possibly WHY it does |
||||
it. |
||||
|
||||
|
||||
Chapter 6: You've made a mess of it |
||||
|
||||
That's OK, we all do. You've probably been told by your long-time Unix |
||||
user helper that "GNU emacs" automatically formats the C sources for |
||||
you, and you've noticed that yes, it does do that, but the defaults it |
||||
uses are less than desirable (in fact, they are worse than random |
||||
typing - a infinite number of monkeys typing into GNU emacs would never |
||||
make a good program). |
||||
|
||||
So, you can either get rid of GNU emacs, or change it to use saner |
||||
values. To do the latter, you can stick the following in your .emacs file: |
||||
|
||||
(defun linux-c-mode () |
||||
"C mode with adjusted defaults for use with the Linux kernel." |
||||
(interactive) |
||||
(c-mode) |
||||
(c-set-style "K&R") |
||||
(setq c-basic-offset 8)) |
||||
|
||||
This will define the M-x linux-c-mode command. When hacking on a |
||||
module, if you put the string -*- linux-c -*- somewhere on the first |
||||
two lines, this mode will be automatically invoked. Also, you may want |
||||
to add |
||||
|
||||
(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode) |
||||
auto-mode-alist)) |
||||
|
||||
to your .emacs file if you want to have linux-c-mode switched on |
||||
automagically when you edit source files under /usr/src/linux. |
||||
|
||||
But even if you fail in getting emacs to do sane formatting, not |
||||
everything is lost: use "indent". |
||||
|
||||
Now, again, GNU indent has the same brain dead settings that GNU emacs |
||||
has, which is why you need to give it a few command line options. |
||||
However, that's not too bad, because even the makers of GNU indent |
||||
recognize the authority of K&R (the GNU people aren't evil, they are |
||||
just severely misguided in this matter), so you just give indent the |
||||
options "-kr -i8" (stands for "K&R, 8 character indents"). |
||||
|
||||
"indent" has a lot of options, and especially when it comes to comment |
||||
re-formatting you may want to take a look at the manual page. But |
||||
remember: "indent" is not a fix for bad programming. |
@ -0,0 +1,11 @@ |
||||
|
||||
include ../config.mk |
||||
|
||||
all: |
||||
@echo "Nothing to do..."
|
||||
|
||||
install: |
||||
@echo "Nothing to do..."
|
||||
|
||||
clean: |
||||
@echo "Nothing to do..."
|
@ -0,0 +1,11 @@ |
||||
|
||||
include ../config.mk |
||||
|
||||
all: |
||||
@echo "Nothing to do..."
|
||||
|
||||
install: |
||||
@echo "Nothing to do..."
|
||||
|
||||
clean: |
||||
@echo "Nothing to do..."
|
@ -0,0 +1,11 @@ |
||||
|
||||
include ../../config.mk |
||||
|
||||
all: |
||||
@echo "Nothing to do..."
|
||||
|
||||
install: |
||||
@echo "Nothing to do..."
|
||||
|
||||
clean: |
||||
@echo "Nothing to do..."
|
@ -0,0 +1,11 @@ |
||||
|
||||
include ../../config.mk |
||||
|
||||
all: |
||||
@echo "Nothing to do..."
|
||||
|
||||
install: |
||||
@echo "Nothing to do..."
|
||||
|
||||
clean: |
||||
@echo "Nothing to do..."
|
@ -0,0 +1,11 @@ |
||||
|
||||
include ../../config.mk |
||||
|
||||
all: |
||||
@echo "Nothing to do..."
|
||||
|
||||
install: |
||||
@echo "Nothing to do..."
|
||||
|
||||
clean: |
||||
@echo "Nothing to do..."
|
@ -0,0 +1,11 @@ |
||||
|
||||
include ../../config.mk |
||||
|
||||
all: |
||||
@echo "Nothing to do..."
|
||||
|
||||
install: |
||||
@echo "Nothing to do..."
|
||||
|
||||
clean: |
||||
@echo "Nothing to do..."
|
Loading…
Reference in new issue