青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

yeqing

C++博客 首頁 新隨筆 聯系 聚合 管理
  1 Posts :: 14 Stories :: 10 Comments :: 0 Trackbacks

Linux下很多程序甚至那些具有圖形用戶界面(graphical user interface,GUI)的程序,都能接受和處理命令行選項。對于某些程序,這是與其他程序或用戶進行交互的主要手段。具有可靠的復雜命令行參數處理機制,會使得您的應用程序更好、更有用。不過很多開發人員都將其寶貴的時間花在了編寫自己的命令行解析器,卻不使用 getopt(),而后者是一個專門設計來減輕命令行處理負擔的庫函數。

?

1、命令行參數
命令行程序設計的首要任務是解析命令行參數,GUI派的程序員很少關心這個。這里,我們對參數(argument)采用了一種比較通俗的定義:命令行上除命令名之外的字符串。參數由多項構成,項與項之間用空白符彼此隔開。
參數進一步分為選項和操作數。選項用于修改程序的默認行為或為程序提供信息,比較老的約定是以短劃線開頭。選項后可以跟隨一些參數,稱為選項參數。剩下的就是操作數了。
2、POSIX約定
POSIX表示可移植操作系統接口:Portable Operating System Interface,電氣和電子工程師協會(Institute of Electrical and Electronics Engineers,IEEE)最初開發 POSIX 標準,是為了提高 UNIX 環境下應用程序的可移植性。然而,POSIX 并不局限于 UNIX。許多其它的操作系統,例如 DEC OpenVMS 和 Microsoft Windows NT,都支持 POSIX 標準。
?

下面是POSIX標準中關于程序名、參數的約定:

程序名不宜少于2個字符且不多于9個字符;
程序名應只包含小寫字母和阿拉伯數字;
選項名應該是單字符活單數字,且以短橫‘-‘為前綴;
多個不需要選項參數的選項,可以合并。(譬如:foo -a -b -c ---->foo -abc)
選項與其參數之間用空白符隔開;
選項參數不可選。
若選項參數有多值,要將其并未一個字串傳進來。譬如:myprog -u "arnold,joe,jane"。這種情況下,需要自己解決這些參數的分離問題。
選項應該在操作數出現之前出現。
特殊參數‘--'指明所有參數都結束了,其后任何參數都認為是操作數。
選項如何排列沒有什么關系,但對互相排斥的選項,如果一個選項的操作結果覆蓋其他選項的操作結果時,最后一個選項起作用;如果選項重復,則順序處理。
允許操作數的順序影響程序行為,但需要作文檔說明。
讀寫指定文件的程序應該將單個參數'-'作為有意義的標準輸入或輸出來對待。
當然許多標準從恒許未遵守以上約定,主要是歷史兼容問題,因為標準出現之前,就已經存在N多程序了。

3、GNU長選項
GNU鼓勵程序員使用--help、--verbose等形式的長選項。這些選項不僅不與POSIX約定沖突,而且容易記憶,另外也提供了在所有GNU工具之間保持一致性的機會。GNU長選項有自己的約定:

對于已經遵循POSIX約定的GNU程序,每個短選項都有一個對應的長選項。
額外針對GNU的長選項不需要對應的短選項,僅僅推薦要有。
長選項可以縮寫成保持惟一性的最短的字串。
選項參數與長選項之間或通過空白字符活通過一個'='來分隔。
選項參數是可選的(只對短選項有效)。
長選項允許以一個短橫線為前綴。

4、基本的命令行處理技術
C程序通過argc和argv參數訪問它的命令行參數。argc是整型數,表示參數的個數(包括命令名)。main()函數的定義方式有兩種,區別僅在于argv如何定義:

int main(int argc, char *argv[])
{
?? ……
} int main(int argc, char **argv)
{
?? ……
}?


當 C 運行時庫的程序啟動代碼調用您的 main() 時,已經對命令行進行了處理。argc 參數包含參數的計數值,而 argv 包含指向這些參數的指針數組。argv[0]是程序名。

一個很簡單的命令行處理技術的例子是echo程序,它可以將參數輸出到標準設備上,用空格符隔開,最后換行。若命令行第一個參數為-n,那么就不會換行。

清單1:

#include <stdio.h>

int main(int argc, char **argv)
{
??? int i, nflg;

??? nflg = 0;
??? if(argc > 1 && argv[1][0] == '-' && argv[1][1] == 'n'){
??????? nflg++;
??????? argc--;
??????? argv++;
??? }
??? for(i=1; i<argc; i++){
??????? fputs(argv[ i ], stdout);
??????? if(i < argc-1)
??????????? putchar(' ');
??? }
??? if(nflg == 0)
??????? putchar('\n');

??? return 0;
}
?

上面代碼中,加亮區域仔細研究一下,會發現很有趣。

echo程序中,對于命令行參數的解析是手動實現的。很久以前,Unix支持小組為了簡化對于命令行參數的解析,開發了getopt()函數,同時提供了幾個外部變量,使得編寫遵守POSIX的代碼變得更加容易了。

5、命令行參數解析函數 —— getopt()
getopt()函數聲明如下:

#include <unistd.h>

int getopt(int argc, char * const argv[], const char *optstring);

extern char *optarg;
extern int optind, opterr, optopt;
?

該函數的argc和argv參數通常直接從main()的參數直接傳遞而來。optstring是選項字母組成的字串。如果該字串里的任一字符后面有冒號,那么這個選項就要求有選項參數。

當給定getopt()命令參數的數量 (argc)、指向這些參數的數組 (argv) 和選項字串 (optstring) 后,getopt() 將返回第一個選項,并設置一些全局變量。使用相同的參數再次調用該函數時,它將返回下一個選項,并設置相應的全局變量。如果不再有可識別的選項,將返回 -1,此任務就完成了。

getopt() 所設置的全局變量包括:

char *optarg——當前選項參數字串(如果有)。
int optind——argv的當前索引值。當getopt()在while循環中使用時,循環結束后,剩下的字串視為操作數,在argv[optind]至argv[argc-1]中可以找到。
int opterr——這個變量非零時,getopt()函數為“無效選項”和“缺少參數選項,并輸出其錯誤信息。

int optopt——當發現無效選項字符之時,getopt()函數或返回'?'字符,或返回':'字符,并且optopt包含了所發現的無效選項字符。
下面就用getopt()來寫個小程序,體驗一下命令行解析的快樂。

程序描述:

程序名:opt_parse_demo

選項:

-n —— 顯示我的名字。
-g —— 顯示我女朋友的名字。
-l —— 帶參數的選項.
清單2:
#include <stdio.h>
#include <unistd.h>

int main (int argc, char **argv)
{
??? int oc;???????????????????? /*選項字符 */
??? char *b_opt_arg;??????????? /*選項參數字串 */

??? while((oc = getopt(argc, argv, "ngl:")) != -1)
??? {
??????? switch(oc)
??????? {
??????????? case 'n':
??????????????? printf("My name is Lyong.\n");
??????????????? break;
??????????? case 'g':
??????????????? printf("Her name is Xxiong.\n");
??????????????? break;
??????????? case 'l':
??????????????? b_opt_arg = optarg;
??????????????? printf("Our love is %s\n", optarg);
??????????????? break;
??????? }
??? }
?? return 0;
}
?

運行結果:

$ ./opt_parse_demo -n
My name is Lyong.
$ ./opt_parse_demo -g
Her name is Xxiong.
$ ./opt_parse_demo -l forever
Our love is forever
$ ./opt_parse_demo -ngl forever
My name is Lyong.
Her name is Xxiong.
Our love is forever
?

6、改變getopt()對錯誤命令行參數信息的輸出行為
不正確的調用程序在所難免,這種錯誤要么是命令行選項無效,要么是缺少選項參數。正常情況下,getopt()會為這兩種情況輸出自己的出錯信息,并且返回'?'。為了驗證此事,可以修改一下上面的清單2中的代碼。

清單3:

#include <stdio.h>
#include <unistd.h>

int main (int argc, char **argv)
{
??? int oc;???????????????????? /*選項字符 */
??? char *b_opt_arg;??????????? /*選項參數字串 */

??? while((oc = getopt(argc, argv, "ngl:")) != -1)
??? {
??????? switch(oc)
??????? {
??????????? case 'n':
??????????????? printf("My name is Lyong.\n");
??????????????? break;
???????????? case 'g':
??????????????? printf("Her name is Xxiong.\n");
??????????????? break;
??????????? case 'l':
??????????????? b_opt_arg = optarg;
??????????????? printf("Our love is %s\n", optarg);
??????????????? break;
??????????? case '?':
??????????????? printf("arguments error!\n");
??????????????? break;
??????? }
??? }
??? return 0;
}
?

輸入一個錯誤的命令行,結果如下:

$ ./opt_parse_demo -l
./opt_parse_demo: option requires an argument -- l
arguments error!
?

很多時候,我們不希望輸出任何錯誤信息,或更希望輸出自己定義的錯誤信息。可以采用以下兩種方法來更改getopt()函數的出錯信息輸出行為:


在調用getopt()之前,將opterr設置為0,這樣就可以在getopt()函數發現錯誤的時候強制它不輸出任何消息。
如果optstring參數的第一個字符是冒號,那么getopt()函數就會保持沉默,并根據錯誤情況返回不同字符,如下:
“無效選項” —— getopt()返回'?',并且optopt包含了無效選項字符(這是正常的行為)。
“缺少選項參數” —— getopt()返回':',如果optstring的第一個字符不是冒號,那么getopt()返回'?',這會使得這種情況不能與無效選項的情況區分開。
多說無益,動手測試一下。

清單4:
#include <stdio.h>
#include <unistd.h>

int main (int argc, char **argv)
{
??? int oc;???????????????????? /*選項字符 */
??? char ec;???????????????????????????? /*無效的選項字符*/
??? char *b_opt_arg;??????????? /*選項參數字串 */

??? while((oc = getopt(argc, argv, ":ngl:")) != -1)
??? {
??????? switch(oc)
??????? {
??????????? case 'n':
??????????????? printf("My name is Lyong.\n");
??????????????? break;
???????????? case 'g':
??????????????? printf("Her name is Xxiong.\n");
??????????????? break;
??????????? case 'l':
??????????????? b_opt_arg = optarg;
??????????????? printf("Our love is %s\n", optarg);
??????????????? break;
??????????? case '?':
??????????????? ec = (char)optopt;
??????????????? printf("無效的選項字符 \' %c \'!\n", ec);
??????????????? break;
??????????? case ':':
??????????????? printf("缺少選項參數!\n");
??????????????? break;
??????? }
??? }
??? return 0;
}

測試結果:

$ ./opt_parse_demo -a
無效的選項字符 ' a '!
$ ./opt_parse_demo -l
缺少選項參數!

7、GNU提供的getopt()函數的特點
上面所設計的getopt()函數是UNIX支持小組提供的,其執行時一碰到不以'-'開始的命令行參數就停止尋找選項。而GNU提供的getopt()函數與之不同,它會掃描整個命令行來尋找選項。當調用GNU getopt()函數并處理命令行參數的時候,它重新排列argv中的元素,這樣當重排結束時,所有選項都被移動到前面并且那些繼續檢查argv[optind]至argv[argc-1]中剩余參數的代碼仍正常工作,但在任何情況下,碰到特殊參數'--'就結束對選項的掃描。

可以輸入一個亂序的命令行,查看opt_parse_demo的輸出:

$ ./opt_parse_demo -l forever a b c d -g -n
Our love is forever
Her name is Xxiong.
My name is Lyong.
?

GNU getopt()第二個特點是可以在optstring中使用特殊的首字符改變getopt()的默認行為:

optstring[0] = '+',這樣就與UNIX支持小組提供的getopt()很相近了。
optstring[0] = '-',會在optarg中得到命令行中的每個參數。
以上兩種情況下,':'可以作為第二個字符使用。
GNU getopt()第三個特點是optstring中的選項字符后面接兩個冒號,就允許該選項有可選的選項參數。在選項參數不存在的情況下,GNU getopt()返回選項字符并將optarg設置為NULL。

8、GNU長選項命令行解析
20 世紀 90 年代,UNIX 應用程序開始支持長選項,即一對短橫線、一個描述性選項名稱,還可以包含一個使用等號連接到選項的參數。

GNU提供了getopt-long()和getopt-long-only()函數支持長選項的命令行解析,其中,后者的長選項字串是以一個短橫線開始的,而非一對短橫線。


getopt_long() 是同時支持長選項和短選項的 getopt() 版本。下面是它們的聲明:

#include <getopt.h>

int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);

int getopt_long_only(int argc, char * const argv[],const char *optstring,const struct option *longopts, int *longindex);

?

getopt_long()的前三個參數與上面的getopt()相同,第4個參數是指向option結構的數組,option結構被稱為“長選項表”。longindex參數如果沒有設置為NULL,那么它就指向一個變量,這個變量會被賦值為尋找到的長選項在longopts中的索引值,這可以用于錯誤診斷。

option結構在getopt.h中的聲明如下:

struct option{
??? const char *name;
??? int has_arg;
??? int *flag;
??? int val;
};
?

對結構中的各元素解釋如下:

const char *name
這是選項名,前面沒有短橫線。譬如"help"、"verbose"之類。

int has_arg
描述了選項是否有選項參數。如果有,是哪種類型的參數,此時,它的值一定是下表中的一個。

符號常量? 數值? 含義?
no_argument? 0 選項沒有參數?
required_argument 1 選項需要參數
?
optional_argument 2 選項參數可選?

int *flag
如果這個指針為NULL,那么getopt_long()返回該結構val字段中的數值。如果該指針不為NULL,getopt_long()會使得它所指向的變量中填入val字段中的數值,并且getopt_long()返回0。如果flag不是NULL,但未發現長選項,那么它所指向的變量的數值不變。

int val
這個值是發現了長選項時的返回值,或者flag不是NULL時載入*flag中的值。典型情況下,若flag不是NULL,那么val是個真/假值,譬如1或0;另一方面,如果flag是NULL,那么val通常是字符常量,若長選項與短選項一致,那么該字符常量應該與optstring中出現的這個選項的參數相同。

每個長選項在長選項表中都有一個單獨條目,該條目里需要填入正確的數值。數組中最后的元素的值應該全是0。數組不需要排序,getopt_long()會進行線性搜索。但是,根據長名字來排序會使程序員讀起來更容易。

以上所說的flag和val的用法看上去有點混亂,但它們很有實用價值,因此有必要搞透徹了。

大部分時候,程序員會根據getopt_long()發現的選項,在選項處理過程中要設置一些標記變量,譬如在使用getopt()時,經常做出如下的程序格式:

int do_name, do_gf_name, do_love; /*標記變量*/
char *b_opt_arg;

while((c = getopt(argc, argv, ":ngl:")) != -1)
{
??? switch (c){
??? case 'n':
??????? do_name = 1;
??? case 'g':
??????? do_gf_name = 1;
??????? break;
??????? break;
??? case 'l':
??????? b_opt_arg = optarg;
??? ……
??? }
}
?

當flag不為NULL時,getopt_long*()會為你設置標記變量。也就是說上面的代碼中,關于選項'n'、'l'的處理,只是設置一些標記,如果flag不為NULL,時,getopt_long()可以自動為各選項所對應的標記變量設置標記,這樣就能夠將上面的switch語句中的兩種種情況減少到了一種。下面給出一個長選項表以及相應處理代碼的例子。

清單5:

#include <stdio.h>
#include <getopt.h>

int do_name, do_gf_name;
char *l_opt_arg;

struct option longopts[] = {
??? { "name",??????? no_argument,??????????? &do_name,??????? 1??? },
??? { "gf_name",??? no_argument,??????????? &do_gf_name,??? 1??? },
??? { "love",??????? required_argument,??? NULL,??????????????? 'l'??? },
??? {???? 0,??? 0,??? 0,??? 0},
};

int main(int argc, char *argv[])
{
??? int c;
???
??? while((c = getopt_long(argc, argv, ":l:", longopts, NULL)) != -1){
??????? switch (c){
??????? case 'l':
??????????? l_opt_arg = optarg;
??????????? printf("Our love is %s!\n", l_opt_arg);
??????????? break;
??????? case 0:
??????????? printf("getopt_long()設置變量 : do_name = %d\n", do_name);
??????????? printf("getopt_long()設置變量 : do_gf_name = %d\n", do_gf_name);
??????????? break;
??????? }
??? }
??? return 0;
}
?

在進行測試之前,再來回顧一下有關option結構中的指針flag的說明吧。

如果這個指針為NULL,那么getopt_long()返回該結構val字段中的數值。如果該指針不為NULL,getopt_long()會使得它所指向的變量中填入val字段中的數值,并且getopt_long()返回0。如果flag不是NULL,但未發現長選項,那么它所指向的變量的數值不變。

下面測試一下:

$ ./long_opt_demo --name
getopt_long()設置變量 : do_name = 1
getopt_long()設置變量 : do_gf_name = 0

$ ./long_opt_demo --gf_name
getopt_long()設置變量 : do_name = 0
getopt_long()設置變量 : do_gf_name = 1

$ ./long_opt_demo --love forever
Our love is forever!

$ ./long_opt_demo -l forever
Our love is forever!

?

測試過后,應該有所感觸了。關于flag和val的討論到此為止。下面總結一下get_long()的各種返回值的含義:

返回值???
?含 義
?
0?????
?getopt_long()設置一個標志,它的值與option結構中的val字段的值一樣
?
1
?每碰到一個命令行參數,optarg都會記錄它
?
'?'
?無效選項
?
':'
?缺少選項參數
?
'x'
?選項字符'x'
?
-1
?選項解析結束
?

從實用的角度來說,我們更期望每個長選項都對應一個短選項,這種情況下,在option結構中,只要將flag設置為NULL,并將val設置為長選項所對應的短選項字符即可。譬如上面清單5中的程序,我們修改如下。

清單6:
#include <stdio.h>
#include <getopt.h>

int do_name, do_gf_name;
char *l_opt_arg;

struct option longopts[] = {
??? { "name",??????? no_argument,??????????? NULL,??????????????? 'n'??? },
??? { "gf_name",??? no_argument,??????????? NULL,??????????????? 'g'??? },
??? { "love",??????? required_argument,??? NULL,??????????????? 'l'??? },
??? {???? 0,??? 0,??? 0,??? 0},
};

int main(int argc, char *argv[])
{
??? int c;
???
??? while((c = getopt_long(argc, argv, ":l:", longopts, NULL)) != -1){
??????? switch (c){
??????? case 'n':
??????????? printf("My name is LYR.\n");
??????????? break;
??????? case 'g':
??????????? printf("Her name is BX.\n");
??????????? break;
??????? case 'l':
??????????? l_opt_arg = optarg;
??????????? printf("Our love is %s!\n", l_opt_arg);
??????????? break;
??????? }
??? }
??? return 0;
}

測試結果如下:


$ ./long_opt_demo --name --gf_name --love forever
My name is LYR.
Her name is BX.
Our love is forever!

$ ./long_opt_demo -ng -l forever
My name is LYR.
Her name is BX.
Our love is forever!
?

9、在LINUX之外的系統平臺上使用GNU getopt()或getopt_long()
只要從GNU程序或GNU C Library(GLIBC)的CVS檔案文件中copy源文件即可(
http://sourceware.org/glibc/ )。所需源文件是getopt.h、getopt.c和getoptl.c,將這些文件包含在你的項目中。另外,你的項目中最好也將COPYING.LIB文件包含進去,因為GNU LGPL(GNU 程序庫公共許可證)的內容全部包括在命名為COPYING.LIB 的文件中。沒事時,可以閱讀一下自由軟件的許可協議,感受一下雷鋒精神。

注意,在包含所需文件之后,在調用getopt_long()系列函數的源代碼中,應該使用#include "getopt.h",而不是#include <getopt.h>,前者會首先在當前目錄中尋找getopt.h。

使用Windows平臺的兄弟可以試用一下,很希望能在這里反饋一下你的使用情況,謝謝。


10、結論
程序需要能夠快速處理各個選項和參數,且要求不會浪費開發人員的太多時間。在這一點上,無論是GUI(圖形用戶交互)程序還是CUI(命令行交互)程序,都是其首要任務,其區別僅在于實現方式的不同。GUI通過菜單、對話框之類的圖形控件來完成交互,而CUI使用了純文本的交互方式。各有利弊吧。在程序開發中,許多測試程序用CUI來完成是首選方案。

getopt() 函數是一個標準庫調用,可允許您使用直接的 while/switch 語句方便地逐個處理命令行參數和檢測選項(帶或不帶附加的參數)。與其類似的 getopt_long() 允許在幾乎不進行額外工作的情況下處理更具描述性的長選項,這非常受開發人員的歡迎。

既然已經知道了如何方便地處理命令行選項,現在就可以集中精力改進您的程序的命令行,可以添加長選項支持,或添加之前由于不想向程序添加額外的命令行選項處理而擱置的任何其他選項。但不要忘記在某處記錄您所有的選項和參數,并提供某種類型的內置幫助函數來為健忘的用戶提供幫助。

posted on 2006-11-29 09:29 夜沁 閱讀(472) 評論(0)  編輯 收藏 引用 所屬分類: linux

只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲精品久久久久久久久| 在线看片成人| 亚洲高清在线观看| 在线精品视频一区二区三四| 亚洲欧洲精品一区二区三区| 午夜精品在线观看| 国产精品午夜视频| 免费一级欧美片在线播放| 99国内精品久久| 亚洲电影一级黄| 久久久国产成人精品| 国产三级精品在线不卡| 欧美粗暴jizz性欧美20| 亚洲精品国产系列| 国产女优一区| 国内精品视频在线观看| 亚洲国产精品毛片| 国产偷国产偷精品高清尤物| 亚洲日本视频| 一区二区三区四区五区在线| 久久久久国产精品一区三寸| 在线观看福利一区| 亚欧成人在线| 欧美中文字幕在线| 欧美巨乳在线观看| 久久久久久久久岛国免费| 欧美理论在线播放| 欧美一区二区三区视频| 欧美高清在线精品一区| 欧美成人dvd在线视频| 国产美女精品在线| 亚洲电影av| 亚洲综合成人婷婷小说| 国产精品视频99| 亚洲最黄网站| 亚洲精品视频在线看| 亚洲精品欧美一区二区三区| 亚洲欧美国产另类| 亚洲一区二区免费在线| 久久久久国内| 亚洲国产高清aⅴ视频| 久久男人av资源网站| 模特精品在线| 亚洲成人在线视频网站| 欧美精品成人91久久久久久久| 亚洲欧美日韩在线| 亚洲国产成人久久综合一区| 国产性猛交xxxx免费看久久| 欧美日韩一区二区视频在线| 久久青青草原一区二区| 久久综合影视| 久久成人资源| 男女精品视频| 亚洲精品久久久久久下一站 | 久久久www| 亚洲精品在线视频| 久久精品二区亚洲w码| 亚洲黄一区二区| 国产亚洲综合性久久久影院| 午夜精品一区二区三区在线播放| 99国产精品自拍| 久久一区二区三区四区五区| 亚洲美女在线视频| 亚洲一区二区三区四区中文| 一本大道久久精品懂色aⅴ| 亚洲网站在线| 亚洲精品日日夜夜| 亚洲午夜激情免费视频| 99re66热这里只有精品3直播| 久久久久久久国产| 亚洲欧美综合精品久久成人| 亚洲第一福利社区| 欧美亚洲第一区| 亚洲国产乱码最新视频| 亚洲女爱视频在线| 亚洲高清视频一区| 中文精品视频| 久久综合一区二区| 一区二区三区高清视频在线观看| 欧美在线观看网站| 国产欧美日韩在线| 亚洲国产女人aaa毛片在线| 亚洲国产天堂久久综合网| 久久激情一区| 欧美精品激情在线观看| 狠狠色综合一区二区| 一区二区三区蜜桃网| 欧美色视频日本高清在线观看| 国产一区二区高清不卡| 激情成人综合网| 久久精品二区亚洲w码| 亚洲精品视频一区| 久久精品免费看| 欧美三级欧美一级| 亚洲经典一区| 亚洲精品视频在线观看免费| 久久亚洲私人国产精品va| 国产一区二区三区在线观看视频| 韩日欧美一区| 亚洲欧美激情一区二区| 欧美大尺度在线观看| 欧美精品乱码久久久久久按摩| 国产精品久久久久91| 伊伊综合在线| 久久夜色精品国产欧美乱| 久久精品成人欧美大片古装| 久久九九有精品国产23| 国产精品99久久久久久久女警| 先锋亚洲精品| 亚洲国产mv| 亚洲综合第一| 欧美日韩在线一区二区三区| 午夜精品久久| 亚洲日本在线视频观看| 欧美激情精品久久久久久| 一区二区av| 一本色道精品久久一区二区三区| 亚洲高清一区二区三区| 久久综合久久综合九色| 99re视频这里只有精品| 羞羞答答国产精品www一本| 亚洲永久免费观看| 欧美电影免费观看| 一本色道久久综合亚洲精品按摩 | 国产精品99久久99久久久二8| 久久偷看各类wc女厕嘘嘘偷窃| 午夜免费电影一区在线观看 | 99视频精品在线| 亚洲深夜福利视频| 亚洲欧美日韩一区二区三区在线观看 | 欧美一区二区视频97| 女同一区二区| 久久亚洲精选| 亚洲国产片色| 亚洲经典自拍| 久久xxxx| 久久婷婷一区| 欧美午夜理伦三级在线观看| 麻豆亚洲精品| 黄色资源网久久资源365| 欧美日韩国产精品成人| 久久国产日韩| 激情成人在线视频| 快播亚洲色图| 欧美ed2k| 亚洲福利小视频| 另类亚洲自拍| 亚洲美女毛片| 日韩亚洲在线| 欧美日韩国产成人精品| 久久国产精品第一页| 亚洲精选一区| 欧美日韩一区二区三区免费| 亚洲精品在线观| 亚洲破处大片| 欧美激情亚洲自拍| 久久久国产精品一区二区中文| 99国产精品99久久久久久粉嫩| 国产三级精品在线不卡| 国产精品啊啊啊| 国产日韩欧美精品综合| 亚洲精品久久久久久下一站 | 国产情人综合久久777777| 亚洲一区在线看| 久久国产精品免费一区| 一区二区三区在线高清| 蜜桃久久精品乱码一区二区| 亚洲经典一区| 午夜精品福利在线观看| 精品99一区二区三区| 欧美精品一区二区三区高清aⅴ| 99国产精品久久久久老师| 欧美在线免费视屏| 亚洲第一精品夜夜躁人人爽| 欧美日韩和欧美的一区二区| 亚洲欧洲99久久| 亚洲国产成人91精品| 亚洲欧美韩国| 久久在线免费观看视频| 欧美精品18| 亚洲网站在线播放| 老司机精品视频一区二区三区| 亚洲日本成人女熟在线观看| 国产精品女人网站| 免费在线成人av| 亚洲欧美一区二区三区极速播放| 蜜臀91精品一区二区三区| 一本色道久久综合狠狠躁的推荐| 国产精品欧美日韩久久| 久久青草福利网站| 亚洲少妇自拍| 久久久噜噜噜久久| 亚洲无限av看| 国产综合香蕉五月婷在线| 牛人盗摄一区二区三区视频| 亚洲一区视频| 免费日韩av电影| 亚洲一区二区三区高清| 欧美美女视频| 久久成人免费视频|